{"record":{"id":"26b78a63876bd891","repo":"JuliusBrussee/caveman","slug":"refusing-to-compress-filepath-filename-looks-se-26b78a","errorCode":null,"errorMessage":"Refusing to compress {filepath}: filename looks sensitive (credentials, keys, secrets, or known private paths). Compression sends file contents to the Anthropic API. Rename the file if this is a false positive.","messagePattern":"Refusing to compress (.+?): filename looks sensitive \\(credentials, keys, secrets, or known private paths\\)\\. Compression sends file contents to the Anthropic API\\. Rename the file if this is a false positive\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/caveman-compress/scripts/compress.py","lineNumber":291,"sourceCode":"\n# ---------- Core Logic ----------\n\n\ndef compress_file(filepath: Path) -> bool:\n    # Resolve and validate path\n    filepath = filepath.resolve()\n    MAX_FILE_SIZE = 500_000  # 500KB\n    if not filepath.exists():\n        raise FileNotFoundError(f\"File not found: {filepath}\")\n    if filepath.stat().st_size > MAX_FILE_SIZE:\n        raise ValueError(f\"File too large to compress safely (max 500KB): {filepath}\")\n\n    # Refuse files that look like they contain secrets or PII. Compressing ships\n    # the raw bytes to the Anthropic API — a third-party boundary — so we fail\n    # loudly rather than silently exfiltrate credentials or keys. Override is\n    # intentional: the user must rename the file if the heuristic is wrong.\n    if is_sensitive_path(filepath):\n        raise ValueError(\n            f\"Refusing to compress {filepath}: filename looks sensitive \"\n            \"(credentials, keys, secrets, or known private paths). \"\n            \"Compression sends file contents to the Anthropic API. \"\n            \"Rename the file if this is a false positive.\"\n        )\n\n    print(f\"Processing: {filepath}\")\n\n    if not should_compress(filepath):\n        print(\"Skipping (not natural language)\")\n        return False\n\n    original_text = filepath.read_text(encoding=\"utf-8\", errors=\"ignore\")\n    # Store backup outside the source directory so skill auto-loaders don't\n    # re-ingest the `.original.md` copy as a live file. Mirror the source's\n    # parent-dir name + stem under a platform-aware base to reduce collisions.\n    backup_dir = backup_dir_for(filepath)\n    backup_path = backup_dir / (filepath.stem + \".original.md\")","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/skills/caveman-compress/scripts/compress.py#L273-L309","documentation":"Raised by compress_file() when is_sensitive_path(filepath) matches — the filename looks like it contains credentials, keys, secrets, or known private paths. Because compression sends raw file bytes to the Anthropic API, the script fails loudly rather than silently exfiltrate. The refusal is intentional: the override is to rename the file, not to bypass the check.","triggerScenarios":"Compressing anything named like .env, id_rsa, credentials.json, *.pem, *.key, tokens.txt, secrets.yaml, or living under a known private path (e.g. ~/.ssh, ~/.aws). The heuristic is filename/path-based, so a false positive on an innocuous file with a scary name also lands here.","commonSituations":"An agent bulk-compressing a directory that includes dotfiles; a legit doc named 'api-keys-overview.md'; CI trying to condense a config directory containing k8s secrets manifests.","solutions":["If the file genuinely holds secrets: do not compress it — exclude it and use a local (non-LLM) compressor instead.","If it is a false positive, rename the file to something that does not match the sensitive heuristic (drop key/secret/credential/pem-style tokens from the name) and re-run.","Audit the file's contents first (grep for key material) before deciding it is safe to ship to a third-party API."],"exampleFix":"# before\ncompress_file(Path('notes/api-keys.md'))  # refused by filename heuristic\n\n# after — verified the file holds no key material, renamed\ncompress_file(Path('notes/api-auth-design.md'))","handlingStrategy":"validation","validationCode":"import re\nSENSITIVE = re.compile(r\"(credential|secret|token|\\.env|id_rsa|\\.pem$|\\.key$|password|\\.ssh|\\.aws)\", re.I)\n\ndef looks_sensitive(path_str: str) -> bool:\n    return bool(SENSITIVE.search(path_str))","typeGuard":null,"tryCatchPattern":"try:\n    compress_file(path)\nexcept ValueError as e:\n    if \"looks sensitive\" in str(e):\n        # inspect the file locally; only rename+retry if truly free of key material\n        maybe_rename_if_safe(path)\n    raise","preventionTips":["Exclude dotfiles, key stores, and secrets-named files from any directory passed to the compress skill.","Scan a file for key material (private-key headers, long base64 secrets) before sending anything to an LLM API.","Rename false positives rather than seeking a bypass flag — the refusal is a deliberate exfiltration guard."],"tags":["security","secrets","llm","exfiltration-guard","validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}