T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_skill.py:120- Finding
Undetected HTTP Response Truncation Can Produce a Misleading Safe Verdict
- Content
View full analysis
Vulnerability Details
File Location:
scripts/analyze_skill.py:120-125, with related completeness handling atscripts/analyze_skill.py:194-197
Vulnerability Type: Incomplete security scanning caused by silent response truncation
Risk Level: MediumVulnerable Code
python def _http_get(url: str, timeout: int = 10) -> str | None: """Fetch URL, return text or None on failure.""" try: req = urllib.request.Request(url, headers={"User-Agent": "skill-trust-auditor/1.0"}) with urllib.request.urlopen(req, timeout=timeout) as resp: raw = resp.read(MAX_FETCH_BYTES) return raw.decode("utf-8", errors="replace")The scanner attempts to reject files that registry metadata identifies as oversized:
python if size and size > MAX_FETCH_BYTES: scan_issues.append(f"oversized_file: {path} size={size}") continueTechnical Analysis
_http_get()reads at mostMAX_FETCH_BYTES—512 KiB—and treats that bounded prefix as the complete response. It does not read one additional byte, compare the response againstContent-Length, or verify the downloaded length and digest against registry metadata.The metadata check only protects the scanner when the registry-provided
sizefield is present and accurate. If the size is absent, zero, understated, or inconsistent with the file endpoint response, the scanner silently analyzes only the first 512 KiB. Noscan_issuesentry is generated in this condition, soscan_completemay remain true.Because the verdict function permits a
SAFEresult whenever the scan is considered complete and the score is sufficiently high, malicious content placed after the download boundary can remain invisible to the detection rules.Attack Path
- An attacker publishes a Skill file with a harmless prefix at least 512 KiB long.
- The attacker places malicious instructions or executable code after the firs ...[truncated 1526 chars]
- Remediation
View remediation
Remediation Suggestions
-
Read one byte beyond the limit and explicitly detect truncation:
python raw = resp.read(MAX_FETCH_BYTES + 1) if len(raw) > MAX_FETCH_BYTES: raise ResponseTooLargeError(url) -
Propagate oversized-response errors into
scan_issuesand forcescan_completetoFalse. -
Validate
Content-Lengthwhen present, while still enforcing the extra-byte check because the header may be absent or inaccurate. -
Compare the downloaded byte count with the registry file-size metadata.
-
Verify file hashes against trusted, exact-version registry metadata when hashes are available.
-
Distinguish transport truncation from decoding and network errors in the report.
-
Add regression tests covering:
- A response larger than 512 KiB with no size metadata.
- Understated registry size metadata.
- Missing
Content-Length. - A response whose actual size differs from registry metadata.
- Confirmation that all these cases produce
UNKNOWNand exit code 2.
-
