Harden clients against untrusted resolver responses; fix SecID encoding - #5
Merged
Merged
Conversation
The resolve API response is attacker-influenceable (a hostile, federated, or MITM'd resolver is in scope), but the three client SDKs surfaced URLs and printed server strings without validation, and encoded the request SecID with a fragile "#"->"%23" replace. Across python/, typescript/, go/: - best_url / bestUrl / BestURL now validate the returned URL's scheme (http/https only); javascript:/data:/file:/relative are rejected (F-08). - CLI output (url, message, corrected SecID) is stripped of C0/C1 control characters to prevent ANSI-escape injection (F-10-02). - Request encoding switched from a hand-rolled "#"->"%23" replace to the standard query encoder (quote(safe="") / encodeURIComponent / url.QueryEscape), which encodes #, &, spaces, etc. (F-10-01). - Python success-path json.loads wrapped to fail cleanly (F-09-01). Regression tests added in all three languages. Also closes the template that generates new clients (F-10-04): BUILD-A-CLIENT.md / PROMPT-TEMPLATE.md now teach full query-encoding and untrusted-response handling instead of the "#"->"%23" replace, so future generated clients inherit the hardening rather than the gaps. npm package renamed to @cloudsecurityalliance/secid (F-10-05, npm scope). PyPI name unchanged (flat namespace; rename TBD). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The SecID resolve API response is attacker-influenceable — a hostile, federated, or MITM'd resolver is in the trust model — but the three client SDKs surfaced returned URLs and printed server-supplied strings without validation, and encoded the request SecID with a fragile
#→%23string replace. This hardens all three languages and fixes the template that generates new clients.Audit reference: SecID-2026-06-14-claude-skill (findings F-08, F-09-01, F-10-01, F-10-02, F-10-04, F-10-05).
Changes (python/ · typescript/ · go/)
best_url/bestUrl/BestURLvalidate the returned URL's scheme —http/httpsonly;javascript:/data:/file:/relative rejected.url,message, corrected SecID) stripped of C0/C1 control chars (incl. ESC) → no ANSI-escape injection.#→%23replace to the standard query encoder (quote(safe="")/encodeURIComponent/url.QueryEscape) — encodes#,&, spaces, etc.json.loadswrapped to fail cleanly on malformed/oversized bodies.Regression tests added in all three languages (Python 24 pass, TS 24 pass, Go suite + 2 new pass).
Template (F-10-04)
skills/build-a-client/BUILD-A-CLIENT.mdandPROMPT-TEMPLATE.mdpreviously taughtreplace("#", "%23")and said nothing about validating the untrusted response — so every future generated client inherited the same gaps. They now teach full query-encoding and untrusted-response handling (scheme validation + output sanitization).Packaging (F-10-05)
npm package renamed to
@cloudsecurityalliance/secid. PyPI name left unchanged (flat namespace; rename TBD). Publishing under the new name + README install-doc updates are a release follow-up, not in this diff.Notes for review
https/httpURLs pass through unchanged, and the colon in identifiers likeRHSA-2024:1234is preserved (validation re-parses; it does not re-encode).🤖 Generated with Claude Code