Security Findings — High Severity
1. Path Traversal via Unsanitized nid in URL Construction
Files:
ts/src/client.ts lines 311, 339
python/numbersprotocol_capture/client.py lines 391, 418
Description:
The nid parameter is interpolated directly into URL paths without validation or encoding:
// TypeScript
`${this.baseUrl}/assets/${nid}/`
# Python
f"{self._base_url}/assets/{nid}/"
The only validation is a truthiness check (if (!nid) / if not nid), which accepts any non-empty string. A malicious nid value containing path traversal characters (e.g., ../../admin/users) or URL-special characters (?, #, @) can alter the target URL, potentially directing authenticated requests (with the Authorization header) to unintended API endpoints.
Impact:
An attacker who controls the nid parameter can craft values like ../../other-endpoint to make the SDK send authenticated requests to arbitrary paths on the API server, or with carefully crafted values containing @ or #, potentially redirect to different hosts entirely. This is a server-side request manipulation vector.
Suggested fix:
Validate that nid matches the expected format (IPFS CIDs typically match ^[a-zA-Z0-9]+$) and/or use encodeURIComponent() / urllib.parse.quote() when embedding it in URL paths. Note that verify.ts already uses encodeURIComponent(nid) for query parameters — the same treatment should be applied in client.ts.
2. Integrity Proof JSON Serialization Mismatch Between TypeScript and Python
Files:
ts/src/crypto.ts line 44
python/numbersprotocol_capture/crypto.py line 71
Description:
The TypeScript signIntegrityProof uses JSON.stringify(proof) which serializes the entire proof object as-is (including any extra properties that may be attached at runtime). The Python sign_integrity_proof explicitly constructs a new dict with exactly three keys in a specific order.
This asymmetry means that if the proof object ever carries additional fields, the TypeScript SDK will silently produce a different integrity hash. The SDKs must produce identical JSON for the same input to ensure cross-language signature interoperability.
Impact:
Cross-language signature verification failures. An asset registered with one SDK could produce mismatched integrity hashes when verified with the other SDK, undermining the core provenance guarantee.
Suggested fix:
In TypeScript, change JSON.stringify(proof) to explicitly construct the object with only the three expected keys in the same order as the Python version:
const proofJson = JSON.stringify({
proof_hash: proof.proof_hash,
asset_mime_type: proof.asset_mime_type,
created_at: proof.created_at,
});
Add a cross-SDK test that verifies both SDKs produce the same integritySha for identical input.
Security Findings — High Severity
1. Path Traversal via Unsanitized
nidin URL ConstructionFiles:
ts/src/client.tslines 311, 339python/numbersprotocol_capture/client.pylines 391, 418Description:
The
nidparameter is interpolated directly into URL paths without validation or encoding:The only validation is a truthiness check (
if (!nid)/if not nid), which accepts any non-empty string. A maliciousnidvalue containing path traversal characters (e.g.,../../admin/users) or URL-special characters (?,#,@) can alter the target URL, potentially directing authenticated requests (with the Authorization header) to unintended API endpoints.Impact:
An attacker who controls the
nidparameter can craft values like../../other-endpointto make the SDK send authenticated requests to arbitrary paths on the API server, or with carefully crafted values containing@or#, potentially redirect to different hosts entirely. This is a server-side request manipulation vector.Suggested fix:
Validate that
nidmatches the expected format (IPFS CIDs typically match^[a-zA-Z0-9]+$) and/or useencodeURIComponent()/urllib.parse.quote()when embedding it in URL paths. Note thatverify.tsalready usesencodeURIComponent(nid)for query parameters — the same treatment should be applied inclient.ts.2. Integrity Proof JSON Serialization Mismatch Between TypeScript and Python
Files:
ts/src/crypto.tsline 44python/numbersprotocol_capture/crypto.pyline 71Description:
The TypeScript
signIntegrityProofusesJSON.stringify(proof)which serializes the entire proof object as-is (including any extra properties that may be attached at runtime). The Pythonsign_integrity_proofexplicitly constructs a new dict with exactly three keys in a specific order.This asymmetry means that if the proof object ever carries additional fields, the TypeScript SDK will silently produce a different integrity hash. The SDKs must produce identical JSON for the same input to ensure cross-language signature interoperability.
Impact:
Cross-language signature verification failures. An asset registered with one SDK could produce mismatched integrity hashes when verified with the other SDK, undermining the core provenance guarantee.
Suggested fix:
In TypeScript, change
JSON.stringify(proof)to explicitly construct the object with only the three expected keys in the same order as the Python version:Add a cross-SDK test that verifies both SDKs produce the same
integrityShafor identical input.