Security Findings — Medium Severity
1. Custom baseUrl Allows SSRF When Used Server-Side
Files:
ts/src/client.ts line 152
python/numbersprotocol_capture/client.py line 158
Description:
Both SDKs accept a custom baseUrl/base_url parameter without any validation. There is no check that the URL uses HTTPS, belongs to a trusted domain, or is even a valid URL. The SDK will then send authenticated requests (including the API token) to whatever URL is provided.
Impact:
In server-side applications where baseUrl might be influenced by configuration or environment variables, this enables SSRF attacks. An attacker can set baseUrl to an internal network address (e.g., http://169.254.169.254/latest/meta-data/) to exfiltrate cloud credentials, or to an attacker-controlled server to capture the API token.
Suggested fix:
Add validation to ensure baseUrl uses HTTPS protocol. Optionally support a configurable allowlist of trusted domains. At minimum, reject http://, private IP ranges, and localhost.
2. No File Size Limits on Asset Registration (DoS via Memory Exhaustion)
Files:
ts/src/client.ts lines 86, 94, 103 (in normalizeFile)
python/numbersprotocol_capture/client.py lines 83, 92, 101 (in _normalize_file)
Description:
Both SDKs read entire files into memory without any size limit. The only validation is that the file is non-empty, but there is no upper bound. In TypeScript, the data is copied a second time for ArrayBuffer conversion, so peak memory is ~2x file size.
Impact:
A large file can cause out-of-memory crashes (denial of service). Particularly dangerous in server-side applications processing user-provided files.
Suggested fix:
Add a configurable maxFileSize parameter (default e.g. 100 MB). For file paths, use fs.stat() / path.stat() to check size before reading. For blobs, check .size property.
3. Python PermissionError Shadows Built-in
File: python/numbersprotocol_capture/errors.py line 35
Description:
The SDK defines a custom PermissionError class that shadows Python's built-in PermissionError (a subclass of OSError). Any code using from numbersprotocol_capture import * will shadow the built-in.
Impact:
except PermissionError blocks in user code will catch SDK API 403 errors but not OS-level file permission errors (or vice versa), causing confusing debugging scenarios.
Suggested fix:
Rename to ForbiddenError or AccessDeniedError to avoid name collision. This is a breaking change requiring a minor/major version bump with a deprecation alias.
4. API Token Sent to Multiple Third-Party Cloud Endpoints
Files:
ts/src/client.ts lines 374-379, 430-436
python/numbersprotocol_capture/client.py lines 449-451, 514-517
Description:
The API token is sent via Authorization header to four distinct third-party endpoints across different providers: the primary API, AWS Lambda, Google Cloud Functions, and Pipedream. Issue #10 covers only the Pipedream endpoint; the AWS Lambda and GCF endpoints also receive the full token.
The AWS Lambda URL uses an auto-generated API Gateway identifier (e23hi68y55), suggesting it may lack production-grade security controls.
Impact:
Broadest possible token exposure surface. If any third-party endpoint is compromised or logs request headers, the token is leaked.
Suggested fix:
Consider using separate, scoped tokens for different endpoints, or route all requests through the primary API. At minimum, document which endpoints receive the token.
5. CI/CD Release Pipeline Missing Integrity Verification
File: .github/workflows/release.yml lines 51-122
Description:
- No CI test gate before publish: Publish jobs depend only on
validate (version check), not on CI tests passing. A tag push can publish even if tests fail.
- Unpinned GitHub Action:
softprops/action-gh-release@v1 uses a mutable tag rather than a pinned SHA.
- No artifact checksums: No verification of built artifacts before publishing.
Impact:
Compromised CI environment or dependency could inject malicious code into published packages without detection.
Suggested fix:
- Add CI test jobs as dependencies of publish jobs.
- Pin
softprops/action-gh-release to a specific commit SHA.
- Add artifact checksum computation and include hashes in release notes.
Security Findings — Medium Severity
1. Custom
baseUrlAllows SSRF When Used Server-SideFiles:
ts/src/client.tsline 152python/numbersprotocol_capture/client.pyline 158Description:
Both SDKs accept a custom
baseUrl/base_urlparameter without any validation. There is no check that the URL uses HTTPS, belongs to a trusted domain, or is even a valid URL. The SDK will then send authenticated requests (including the API token) to whatever URL is provided.Impact:
In server-side applications where
baseUrlmight be influenced by configuration or environment variables, this enables SSRF attacks. An attacker can setbaseUrlto an internal network address (e.g.,http://169.254.169.254/latest/meta-data/) to exfiltrate cloud credentials, or to an attacker-controlled server to capture the API token.Suggested fix:
Add validation to ensure
baseUrluses HTTPS protocol. Optionally support a configurable allowlist of trusted domains. At minimum, rejecthttp://, private IP ranges, and localhost.2. No File Size Limits on Asset Registration (DoS via Memory Exhaustion)
Files:
ts/src/client.tslines 86, 94, 103 (innormalizeFile)python/numbersprotocol_capture/client.pylines 83, 92, 101 (in_normalize_file)Description:
Both SDKs read entire files into memory without any size limit. The only validation is that the file is non-empty, but there is no upper bound. In TypeScript, the data is copied a second time for
ArrayBufferconversion, so peak memory is ~2x file size.Impact:
A large file can cause out-of-memory crashes (denial of service). Particularly dangerous in server-side applications processing user-provided files.
Suggested fix:
Add a configurable
maxFileSizeparameter (default e.g. 100 MB). For file paths, usefs.stat()/path.stat()to check size before reading. For blobs, check.sizeproperty.3. Python
PermissionErrorShadows Built-inFile:
python/numbersprotocol_capture/errors.pyline 35Description:
The SDK defines a custom
PermissionErrorclass that shadows Python's built-inPermissionError(a subclass ofOSError). Any code usingfrom numbersprotocol_capture import *will shadow the built-in.Impact:
except PermissionErrorblocks in user code will catch SDK API 403 errors but not OS-level file permission errors (or vice versa), causing confusing debugging scenarios.Suggested fix:
Rename to
ForbiddenErrororAccessDeniedErrorto avoid name collision. This is a breaking change requiring a minor/major version bump with a deprecation alias.4. API Token Sent to Multiple Third-Party Cloud Endpoints
Files:
ts/src/client.tslines 374-379, 430-436python/numbersprotocol_capture/client.pylines 449-451, 514-517Description:
The API token is sent via Authorization header to four distinct third-party endpoints across different providers: the primary API, AWS Lambda, Google Cloud Functions, and Pipedream. Issue #10 covers only the Pipedream endpoint; the AWS Lambda and GCF endpoints also receive the full token.
The AWS Lambda URL uses an auto-generated API Gateway identifier (
e23hi68y55), suggesting it may lack production-grade security controls.Impact:
Broadest possible token exposure surface. If any third-party endpoint is compromised or logs request headers, the token is leaked.
Suggested fix:
Consider using separate, scoped tokens for different endpoints, or route all requests through the primary API. At minimum, document which endpoints receive the token.
5. CI/CD Release Pipeline Missing Integrity Verification
File:
.github/workflows/release.ymllines 51-122Description:
validate(version check), not on CI tests passing. A tag push can publish even if tests fail.softprops/action-gh-release@v1uses a mutable tag rather than a pinned SHA.Impact:
Compromised CI environment or dependency could inject malicious code into published packages without detection.
Suggested fix:
softprops/action-gh-releaseto a specific commit SHA.