{"data":{"skill":{"slug":"kochetkov-ma-brewpage-publish","name":"brewpage-publish","icon":"📦","repo":"https://github.com/kochetkov-ma/claude-brewcode/tree/d2d42282fecec988447f9c9547959b31a8012644/skills/brewpage-publish","status":"approved","author":"kochetkov-ma","authorVersion":null,"skillstoreRevision":4},"audit":{"id":"4d7efaea-023d-47ad-9313-d784dbeb5e0d","skill_id":"4bf85c8e-ddad-4143-9c98-4b5fde9536c8","version":7,"content_hash":"v3:d0890ce2c604a2d107a7fc44f7c85f24a072fbe5:b15355ed8c401f28f23f94bd44f7148b639bc6979c8955de9f937244b1dcad27:f3abe8d11326c4a5221e89a47b3f1b04ea2be77e9acacec3ace7ba2bb4467262:736b696c6c732f6b6f636865746b6f762d6d612f62726577706167652d7075626c697368:e09230caf2dc8c6c9e90ad06f5af86e8","risk_level":"medium","is_blocked":false,"safe_to_publish":true,"analysis_status":"ok","agent_auto_install_policy":"allowed","manual_install_policy":"allowed","summary":"All 261 static findings are false positives involving documentation, defensive checks, or intended publishing operations. No evidence found of credential theft, encoded payloads, or audit-directed prompt injection. One semantic risk remains: a concurrently modified source ZIP can bypass archive inspection and sensitive-entry confirmation before upload.","remediation":[{"issue":"Supplied ZIP inspection and upload independently reopen a mutable source path, so the uploaded bytes can differ from the inspected bytes.","severity":"medium","suggestion":"Copy the ZIP into the private run directory using a bounded read. Inspect and upload only that protected snapshot, then remove it during cleanup."}],"risk_factor_evidence":[{"factor":"network","evidence":[{"file":"LICENSE","line_end":3,"line_start":3},{"file":"README.md","line_end":115,"line_start":115},{"file":"README.md","line_end":125,"line_start":125},{"file":"scripts/brewpage-lib.sh","line_end":51,"line_start":51},{"file":"scripts/brewpage-run.sh","line_end":73,"line_start":73},{"file":"scripts/brewpage-run.sh","line_end":180,"line_start":180},{"file":"scripts/brewpage-run.sh","line_end":186,"line_start":186},{"file":"scripts/brewpage-run.sh","line_end":191,"line_start":191},{"file":"scripts/brewpage-run.sh","line_end":206,"line_start":206},{"file":"SKILL.md","line_end":84,"line_start":84},{"file":"SKILL.md","line_end":198,"line_start":198},{"file":"SKILL.md","line_end":206,"line_start":206},{"file":"SKILL.md","line_end":262,"line_start":262},{"file":"SKILL.md","line_end":263,"line_start":263}]},{"factor":"external_commands","evidence":[{"file":"scripts/brewpage-lib.sh","line_end":51,"line_start":51},{"file":"scripts/brewpage-lib.sh","line_end":52,"line_start":52},{"file":"scripts/brewpage-lib.sh","line_end":62,"line_start":62},{"file":"scripts/brewpage-lib.sh","line_end":65,"line_start":65},{"file":"scripts/brewpage-lib.sh","line_end":166,"line_start":166},{"file":"scripts/brewpage-lib.sh","line_end":187,"line_start":187},{"file":"scripts/brewpage-lib.sh","line_end":8,"line_start":8},{"file":"scripts/brewpage-lib.sh","line_end":9,"line_start":9},{"file":"scripts/brewpage-lib.sh","line_end":10,"line_start":10},{"file":"scripts/brewpage-lib.sh","line_end":21,"line_start":21},{"file":"scripts/brewpage-lib.sh","line_end":32,"line_start":32},{"file":"scripts/brewpage-lib.sh","line_end":37,"line_start":37},{"file":"scripts/brewpage-lib.sh","line_end":47,"line_start":47},{"file":"scripts/brewpage-lib.sh","line_end":63,"line_start":63},{"file":"scripts/brewpage-lib.sh","line_end":66,"line_start":66},{"file":"scripts/brewpage-lib.sh","line_end":105,"line_start":105},{"file":"scripts/brewpage-lib.sh","line_end":190,"line_start":190},{"file":"scripts/brewpage-lib.sh","line_end":192,"line_start":192},{"file":"scripts/brewpage-lib.sh","line_end":199,"line_start":199},{"file":"scripts/brewpage-lib.sh","line_end":201,"line_start":201},{"file":"scripts/brewpage-lib.sh","line_end":202,"line_start":202},{"file":"scripts/brewpage-lib.sh","line_end":204,"line_start":204},{"file":"scripts/brewpage-lib.sh","line_end":229,"line_start":229},{"file":"scripts/brewpage-lib.sh","line_end":65,"line_start":62},{"file":"scripts/brewpage-lib.sh","line_end":166,"line_start":65},{"file":"scripts/brewpage-run.sh","line_end":6,"line_start":6},{"file":"scripts/brewpage-run.sh","line_end":25,"line_start":25},{"file":"scripts/brewpage-run.sh","line_end":47,"line_start":47},{"file":"scripts/brewpage-run.sh","line_end":49,"line_start":49},{"file":"scripts/brewpage-run.sh","line_end":52,"line_start":52},{"file":"scripts/brewpage-run.sh","line_end":55,"line_start":55},{"file":"scripts/brewpage-run.sh","line_end":56,"line_start":56},{"file":"scripts/brewpage-run.sh","line_end":58,"line_start":58},{"file":"scripts/brewpage-run.sh","line_end":61,"line_start":61},{"file":"scripts/brewpage-run.sh","line_end":62,"line_start":62},{"file":"scripts/brewpage-run.sh","line_end":73,"line_start":73},{"file":"scripts/brewpage-run.sh","line_end":103,"line_start":103},{"file":"scripts/brewpage-run.sh","line_end":126,"line_start":126},{"file":"scripts/brewpage-run.sh","line_end":127,"line_start":127},{"file":"scripts/brewpage-run.sh","line_end":128,"line_start":128},{"file":"scripts/brewpage-run.sh","line_end":181,"line_start":180},{"file":"scripts/brewpage-run.sh","line_end":187,"line_start":186},{"file":"scripts/brewpage-run.sh","line_end":191,"line_start":191},{"file":"scripts/brewpage-run.sh","line_end":197,"line_start":197},{"file":"scripts/brewpage-run.sh","line_end":202,"line_start":202},{"file":"scripts/brewpage-run.sh","line_end":206,"line_start":206},{"file":"scripts/brewpage-run.sh","line_end":207,"line_start":207},{"file":"scripts/history.py","line_end":55,"line_start":55},{"file":"scripts/publish.mjs","line_end":4,"line_start":4},{"file":"scripts/publish.mjs","line_end":153,"line_start":153}]},{"factor":"filesystem","evidence":[{"file":"scripts/brewpage-lib.sh","line_end":84,"line_start":84},{"file":"scripts/brewpage-lib.sh","line_end":10,"line_start":10},{"file":"scripts/brewpage-lib.sh","line_end":14,"line_start":14},{"file":"scripts/brewpage-lib.sh","line_end":28,"line_start":28},{"file":"scripts/brewpage-lib.sh","line_end":38,"line_start":38},{"file":"scripts/brewpage-lib.sh","line_end":8,"line_start":8},{"file":"scripts/brewpage-lib.sh","line_end":9,"line_start":9},{"file":"scripts/brewpage-lib.sh","line_end":10,"line_start":10},{"file":"scripts/brewpage-lib.sh","line_end":21,"line_start":21},{"file":"scripts/brewpage-lib.sh","line_end":46,"line_start":46},{"file":"scripts/brewpage-lib.sh","line_end":132,"line_start":132},{"file":"scripts/brewpage-lib.sh","line_end":133,"line_start":133},{"file":"scripts/brewpage-lib.sh","line_end":148,"line_start":148},{"file":"scripts/brewpage-lib.sh","line_end":160,"line_start":160},{"file":"scripts/brewpage-lib.sh","line_end":183,"line_start":183},{"file":"scripts/brewpage-lib.sh","line_end":196,"line_start":196},{"file":"scripts/brewpage-lib.sh","line_end":212,"line_start":212},{"file":"scripts/brewpage-lib.sh","line_end":93,"line_start":93},{"file":"scripts/brewpage-run.sh","line_end":62,"line_start":62},{"file":"scripts/brewpage-run.sh","line_end":71,"line_start":71},{"file":"scripts/brewpage-run.sh","line_end":77,"line_start":77},{"file":"scripts/brewpage-run.sh","line_end":134,"line_start":134},{"file":"scripts/brewpage-run.sh","line_end":185,"line_start":185},{"file":"scripts/history.py","line_end":33,"line_start":33},{"file":"scripts/history.py","line_end":41,"line_start":41},{"file":"scripts/publish.mjs","line_end":5,"line_start":5},{"file":"scripts/publish.mjs","line_end":44,"line_start":44},{"file":"scripts/publish.mjs","line_end":110,"line_start":110},{"file":"scripts/publish.mjs","line_end":201,"line_start":201},{"file":"SKILL.md","line_end":197,"line_start":197},{"file":"SKILL.md","line_end":205,"line_start":205},{"file":"SKILL.md","line_end":244,"line_start":244}]},{"factor":"env_access","evidence":[{"file":"scripts/history.py","line_end":55,"line_start":55},{"file":"scripts/history.py","line_end":65,"line_start":65},{"file":"scripts/publish.mjs","line_end":139,"line_start":139},{"file":"scripts/publish.mjs","line_end":140,"line_start":140},{"file":"scripts/publish.mjs","line_end":139,"line_start":139},{"file":"scripts/publish.mjs","line_end":140,"line_start":140}]}],"critical_findings":[],"high_findings":[],"medium_findings":[{"title":"Archive Validation Is Not Bound to Uploaded Bytes","locations":[{"file":"scripts/brewpage-run.sh","line_end":207,"line_start":200}],"confidence":0.94,"description":"The supplied ZIP is inspected, then curl reopens its original path for upload. A concurrent writer can replace its contents between steps, bypassing archive checks and sensitive-entry confirmation.","review_kind":"security","source_category":"semantic","source_severity":"medium","confidence_reasoning":"The site-zip branch assigns the original path to archive and passes that path separately to inspection and curl. Exploitation requires concurrent source write access."}],"low_findings":[],"dangerous_patterns":[],"files_scanned":7,"total_lines":1268,"audit_model":"codex","audited_at":"2026-10-27T04:04:54.838+00:00","created_at":"2026-10-27T04:35:40.888455+00:00","static_findings":[{"id":"network:LICENSE:3:hardcoded-url","file":"LICENSE","pattern":"Hardcoded URL","snippet":"Copyright (c) 2025-2026 Maksim Kochetkov (kochetkov-ma), https://github.com/kochetkov-ma/claude-brew","category":"network","line_end":3,"severity":"low","line_start":3},{"id":"network:README.md:115:hardcoded-url","file":"README.md","pattern":"Hardcoded URL","snippet":"curl -X DELETE \"https://brewpage.app/api/{type}/{ns}/{id}\" -H \"X-Owner-Token: {token}\"","category":"network","line_end":115,"severity":"low","line_start":115},{"id":"network:README.md:125:hardcoded-url","file":"README.md","pattern":"Hardcoded URL","snippet":"claude plugin marketplace add https://github.com/kochetkov-ma/claude-brewcode","category":"network","line_end":125,"severity":"low","line_start":125},{"id":"sensitive:README.md:68:environment-file-access","file":"README.md","pattern":"Environment file access","snippet":"The directory bundle is **allowlisted**: it drops system files (`.DS_Store`, `__MACOSX/`, `Thumbs.db","category":"sensitive","line_end":68,"severity":"high","line_start":68},{"id":"sensitive:README.md:68:sqlite-database-file","file":"README.md","pattern":"SQLite database file","snippet":"The directory bundle is **allowlisted**: it drops system files (`.DS_Store`, `__MACOSX/`, `Thumbs.db","category":"sensitive","line_end":68,"severity":"medium","line_start":68},{"id":"blocker:README.md:89:system-reconnaissance","file":"README.md","pattern":"System reconnaissance","snippet":"An upload may return an existing publication. Keep that winner's identity, metadata and exact server","category":"blocker","line_end":89,"severity":"low","line_start":89},{"id":"external_commands:scripts/brewpage-lib.sh:51:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"> Delete: `curl -s -X DELETE \"<Owner API>\" -H \"X-Owner-Token: TOKEN\"`; rows without one: `https://br","category":"external_commands","line_end":51,"severity":"medium","line_start":51},{"id":"external_commands:scripts/brewpage-lib.sh:52:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"> Update a site (same URL; old publications answer 409, see above): `PUT /api/sites/<ns>/<id>` with ","category":"external_commands","line_end":52,"severity":"medium","line_start":52},{"id":"external_commands:scripts/brewpage-lib.sh:62:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"printf '| %s | [%s](%s) | `%s` | %sd | %s | %s | `%s` |\\n' \\","category":"external_commands","line_end":62,"severity":"medium","line_start":62},{"id":"external_commands:scripts/brewpage-lib.sh:65:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"printf '| %s | [%s](%s) | `%s` | %sd | %s |\\n' \\","category":"external_commands","line_end":65,"severity":"medium","line_start":65},{"id":"external_commands:scripts/brewpage-lib.sh:166:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"# A function has its own positional parameters, so no `set --` juggling is needed.","category":"external_commands","line_end":166,"severity":"medium","line_start":166},{"id":"external_commands:scripts/brewpage-lib.sh:187:ruby-shell-backtick-execution","file":"scripts/brewpage-lib.sh","pattern":"Ruby/shell backtick execution","snippet":"# `site` is the only type whose response carries .fileCount.","category":"external_commands","line_end":187,"severity":"medium","line_start":187},{"id":"external_commands:scripts/brewpage-lib.sh:8:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"p=$(cd \"$1\" 2>/dev/null && pwd -P) || return 1","category":"external_commands","line_end":8,"severity":"medium","line_start":8},{"id":"external_commands:scripts/brewpage-lib.sh:9:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"[ -n \"${HOME:-}\" ] && [ \"$p\" = \"$(cd \"$HOME\" 2>/dev/null && pwd -P)\" ] && return 0","category":"external_commands","line_end":9,"severity":"medium","line_start":9},{"id":"external_commands:scripts/brewpage-lib.sh:10:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"[ -n \"${CLAUDE_CONFIG_DIR:-}\" ] && [ \"$p/.claude\" = \"$(cd \"$CLAUDE_CONFIG_DIR\" 2>/dev/null && pwd -P","category":"external_commands","line_end":10,"severity":"medium","line_start":10},{"id":"external_commands:scripts/brewpage-lib.sh:21:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"root=$(git rev-parse --show-toplevel 2>/dev/null) || root=\"\"","category":"external_commands","line_end":21,"severity":"medium","line_start":21},{"id":"external_commands:scripts/brewpage-lib.sh:32:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"d=$(dirname \"$d\")","category":"external_commands","line_end":32,"severity":"medium","line_start":32},{"id":"external_commands:scripts/brewpage-lib.sh:37:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"BP_ROOT=\"$(bp_project_root)\"","category":"external_commands","line_end":37,"severity":"medium","line_start":37},{"id":"external_commands:scripts/brewpage-lib.sh:47:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"python3 \"$(dirname \"${BASH_SOURCE[0]}\")/history.py\" init \"$BP_ROOT\" \"${HISTORY_FILE#\"$BP_ROOT/\"}\" <<","category":"external_commands","line_end":47,"severity":"medium","line_start":47},{"id":"external_commands:scripts/brewpage-lib.sh:63:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"\"$(date '+%Y-%m-%d %H:%M')\" \"$1\" \"$1\" \"$2\" \"$3\" \"$4\" \"$5\" \"${6:-}\" | python3 \"$(dirname \"${BASH_SOUR","category":"external_commands","line_end":63,"severity":"medium","line_start":63},{"id":"external_commands:scripts/brewpage-lib.sh:66:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"\"$(date '+%Y-%m-%d %H:%M')\" \"$1\" \"$1\" \"$2\" \"$3\" \"$4\" | python3 \"$(dirname \"${BASH_SOURCE[0]}\")/histo","category":"external_commands","line_end":66,"severity":"medium","line_start":66},{"id":"external_commands:scripts/brewpage-lib.sh:105:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"[ -n \"$(find \"$BP_RUN_DIR\" -maxdepth 0 -type d -perm 0700 -print)\" ] || {","category":"external_commands","line_end":105,"severity":"medium","line_start":105},{"id":"external_commands:scripts/brewpage-lib.sh:190:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"url=$(printf '%s' \"$response\" | jq -r '.link // empty')","category":"external_commands","line_end":190,"severity":"medium","line_start":190},{"id":"external_commands:scripts/brewpage-lib.sh:192:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"reason=$(bp_error_reason \"$response\")","category":"external_commands","line_end":192,"severity":"medium","line_start":192},{"id":"external_commands:scripts/brewpage-lib.sh:199:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"token=$(printf '%s' \"$response\" | jq -r '.ownerToken // empty')","category":"external_commands","line_end":199,"severity":"medium","line_start":199},{"id":"external_commands:scripts/brewpage-lib.sh:201:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"owner_api=$(printf '%s' \"$response\" | jq -r '.ownerLink // empty')","category":"external_commands","line_end":201,"severity":"medium","line_start":201},{"id":"external_commands:scripts/brewpage-lib.sh:202:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"identity=$(printf '%s' \"$response\" | jq -c '{id, namespace, type, routingCohort, deliveryMode, modeL","category":"external_commands","line_end":202,"severity":"medium","line_start":202},{"id":"external_commands:scripts/brewpage-lib.sh:204:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"fcount=$(printf '%s' \"$response\" | jq -r '.fileCount // \"?\"')","category":"external_commands","line_end":204,"severity":"medium","line_start":204},{"id":"external_commands:scripts/brewpage-lib.sh:229:shell-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Shell command substitution","snippet":"ENTRY=$(printf '%s\\n' \"$manifest\" | sed -n 's/^ENTRY: //p')","category":"external_commands","line_end":229,"severity":"medium","line_start":229},{"id":"external_commands:scripts/brewpage-lib.sh:62:template-literal-with-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Template literal with command substitution","snippet":"printf '| %s | [%s](%s) | `%s` | %sd | %s | %s | `%s` |\\n' \\","category":"external_commands","line_end":65,"severity":"medium","line_start":62},{"id":"external_commands:scripts/brewpage-lib.sh:65:template-literal-with-command-substitution","file":"scripts/brewpage-lib.sh","pattern":"Template literal with command substitution","snippet":"printf '| %s | [%s](%s) | `%s` | %sd | %s |\\n' \\","category":"external_commands","line_end":166,"severity":"medium","line_start":65},{"id":"network:scripts/brewpage-lib.sh:51:hardcoded-url","file":"scripts/brewpage-lib.sh","pattern":"Hardcoded URL","snippet":"> Delete: `curl -s -X DELETE \"<Owner API>\" -H \"X-Owner-Token: TOKEN\"`; rows without one: `https://br","category":"network","line_end":51,"severity":"low","line_start":51},{"id":"filesystem:scripts/brewpage-lib.sh:84:path-traversal-sequence","file":"scripts/brewpage-lib.sh","pattern":"Path traversal sequence","snippet":"*[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._/-]* | */../* | ../* | */..) echo","category":"filesystem","line_end":84,"severity":"high","line_start":84},{"id":"filesystem:scripts/brewpage-lib.sh:10:hidden-file-access","file":"scripts/brewpage-lib.sh","pattern":"Hidden file access","snippet":"[ -n \"${CLAUDE_CONFIG_DIR:-}\" ] && [ \"$p/.claude\" = \"$(cd \"$CLAUDE_CONFIG_DIR\" 2>/dev/null && pwd -P","category":"filesystem","line_end":10,"severity":"medium","line_start":10},{"id":"filesystem:scripts/brewpage-lib.sh:14:hidden-file-access","file":"scripts/brewpage-lib.sh","pattern":"Hidden file access","snippet":"# walk for .git/.claude (profile parents skipped) -> PWD. The history file must not follow a nested ","category":"filesystem","line_end":14,"severity":"medium","line_start":14},{"id":"filesystem:scripts/brewpage-lib.sh:28:hidden-file-access","file":"scripts/brewpage-lib.sh","pattern":"Hidden file access","snippet":"if [ -d \"$d/.git\" ] || { [ -d \"$d/.claude\" ] && ! bp_is_profile_parent \"$d\"; }; then","category":"filesystem","line_end":28,"severity":"medium","line_start":28},{"id":"filesystem:scripts/brewpage-lib.sh:38:hidden-file-access","file":"scripts/brewpage-lib.sh","pattern":"Hidden file access","snippet":"HISTORY_FILE=\"$BP_ROOT/.claude/brewpage-history.md\"","category":"filesystem","line_end":38,"severity":"medium","line_start":38},{"id":"filesystem:scripts/brewpage-lib.sh:8:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"p=$(cd \"$1\" 2>/dev/null && pwd -P) || return 1","category":"filesystem","line_end":8,"severity":"low","line_start":8},{"id":"filesystem:scripts/brewpage-lib.sh:9:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"[ -n \"${HOME:-}\" ] && [ \"$p\" = \"$(cd \"$HOME\" 2>/dev/null && pwd -P)\" ] && return 0","category":"filesystem","line_end":9,"severity":"low","line_start":9},{"id":"filesystem:scripts/brewpage-lib.sh:10:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"[ -n \"${CLAUDE_CONFIG_DIR:-}\" ] && [ \"$p/.claude\" = \"$(cd \"$CLAUDE_CONFIG_DIR\" 2>/dev/null && pwd -P","category":"filesystem","line_end":10,"severity":"low","line_start":10},{"id":"filesystem:scripts/brewpage-lib.sh:21:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"root=$(git rev-parse --show-toplevel 2>/dev/null) || root=\"\"","category":"filesystem","line_end":21,"severity":"low","line_start":21},{"id":"filesystem:scripts/brewpage-lib.sh:46:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"command -v python3 >/dev/null || { echo 'FAILED: python3 required for secure history'; return 1; }","category":"filesystem","line_end":46,"severity":"low","line_start":46},{"id":"filesystem:scripts/brewpage-lib.sh:132:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"command -v jq >/dev/null || { echo \"FAILED: jq required\"; return 1; }","category":"filesystem","line_end":132,"severity":"low","line_start":132},{"id":"filesystem:scripts/brewpage-lib.sh:133:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"jq -ner --rawfile password \"$1\" \"$BP_PW_FILTER\" >/dev/null 2>&1 ||","category":"filesystem","line_end":133,"severity":"low","line_start":133},{"id":"filesystem:scripts/brewpage-lib.sh:148:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"command -v jq >/dev/null || { echo \"FAILED: jq required\"; return 1; }","category":"filesystem","line_end":148,"severity":"low","line_start":148},{"id":"filesystem:scripts/brewpage-lib.sh:160:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"(umask 077; jq -ner --rawfile password \"$password_file\" \"$BP_PW_FILTER\" > \"$BP_HEADER_FILE\") 2>/dev/","category":"filesystem","line_end":160,"severity":"low","line_start":160},{"id":"filesystem:scripts/brewpage-lib.sh:183:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"| \"HTTP \\(.status): \\((.message // .error // \"\") | tostring | explode | map(if . < 32 then 32 else .","category":"filesystem","line_end":183,"severity":"low","line_start":183},{"id":"filesystem:scripts/brewpage-lib.sh:196:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"if printf '%s' \"$response\" | jq -e '.result.action == \"merged\" and .result.extras.isOwner == false' ","category":"filesystem","line_end":196,"severity":"low","line_start":196},{"id":"filesystem:scripts/brewpage-lib.sh:212:standard-device-file-access","file":"scripts/brewpage-lib.sh","pattern":"Standard device file access","snippet":"printf '%s' \"$response\" | jq -r '.notices[]?.message // empty | \"NOTICE: \" + (tostring | explode | m","category":"filesystem","line_end":212,"severity":"low","line_start":212},{"id":"filesystem:scripts/brewpage-lib.sh:93:temp-file-creation","file":"scripts/brewpage-lib.sh","pattern":"Temp file creation","snippet":"(umask 077; mktemp -d \"$BP_TMPDIR/brewpage.XXXXXX\")","category":"filesystem","line_end":93,"severity":"low","line_start":93},{"id":"blocker:scripts/brewpage-lib.sh:100:system-reconnaissance","file":"scripts/brewpage-lib.sh","pattern":"System reconnaissance","snippet":"*) echo \"FAILED: invalid publish run id\"; return 1 ;;","category":"blocker","line_end":100,"severity":"low","line_start":100},{"id":"blocker:scripts/brewpage-lib.sh:102:system-reconnaissance","file":"scripts/brewpage-lib.sh","pattern":"System reconnaissance","snippet":"case \"$id\" in *[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.]*) echo \"FAILED: in","category":"blocker","line_end":102,"severity":"low","line_start":102},{"id":"blocker:scripts/brewpage-lib.sh:125:system-reconnaissance","file":"scripts/brewpage-lib.sh","pattern":"System reconnaissance","snippet":"then \"X-Password: \" + $p else error(\"invalid password\") end'","category":"blocker","line_end":125,"severity":"low","line_start":125},{"id":"blocker:scripts/brewpage-lib.sh:127:system-reconnaissance","file":"scripts/brewpage-lib.sh","pattern":"System reconnaissance","snippet":"# {password_file} slot: absolute path to a readable non-symlink regular file with a valid password.","category":"blocker","line_end":127,"severity":"low","line_start":127},{"id":"blocker:scripts/brewpage-lib.sh:215:network-reconnaissance","file":"scripts/brewpage-lib.sh","pattern":"Network reconnaissance","snippet":"# publish.mjs verdict for both site blocks: success -> ENTRY from manifest; else rc 2 (needs human O","category":"blocker","line_end":215,"severity":"low","line_start":215},{"id":"external_commands:scripts/brewpage-run.sh:6:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"HERE=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"","category":"external_commands","line_end":6,"severity":"medium","line_start":6},{"id":"external_commands:scripts/brewpage-run.sh:25:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"BP_FRESH=$(bp_prepare) || die \"cannot allocate a private run directory\"","category":"external_commands","line_end":25,"severity":"medium","line_start":25},{"id":"external_commands:scripts/brewpage-run.sh:47:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"abs=$(cd \"$p\" && pwd -P)","category":"external_commands","line_end":47,"severity":"medium","line_start":47},{"id":"external_commands:scripts/brewpage-run.sh:49:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"html_files=$(cd \"$abs\" && find . -type f \\( -name '*.html' -o -name '*.htm' \\) | sed 's|^\\./||' | LC","category":"external_commands","line_end":49,"severity":"medium","line_start":49},{"id":"external_commands:scripts/brewpage-run.sh:52:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"entry=$(printf '%s\\n' \"$html_files\" | awk -F/ 'NF { print NF \"\\t\" $0 }' | LC_ALL=C sort -s -n -k1,1 ","category":"external_commands","line_end":52,"severity":"medium","line_start":52},{"id":"external_commands:scripts/brewpage-run.sh:55:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"\"$(find \"$abs\" -type f | wc -l | tr -d ' ')\" \"$(printf '%s' \"$html_files\" | grep -c . || true)\" \\","category":"external_commands","line_end":55,"severity":"medium","line_start":55},{"id":"external_commands:scripts/brewpage-run.sh:56:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"\"$(du -sk \"$abs\" | cut -f1)\" \"${entry:-none}\"","category":"external_commands","line_end":56,"severity":"medium","line_start":56},{"id":"external_commands:scripts/brewpage-run.sh:58:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"abs=\"$(cd \"$(dirname \"$p\")\" && pwd -P)/$(basename \"$p\")\"","category":"external_commands","line_end":58,"severity":"medium","line_start":58},{"id":"external_commands:scripts/brewpage-run.sh:61:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"printf 'TYPE: %s\\nPATH: %s\\nBYTES: %s\\nMIME: %s\\n' \"$type\" \"$abs\" \"$(wc -c < \"$abs\" | tr -d ' ')\" \\","category":"external_commands","line_end":61,"severity":"medium","line_start":61},{"id":"external_commands:scripts/brewpage-run.sh:62:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"\"$(file --mime-type -b -- \"$abs\" 2>/dev/null || echo unknown)\"","category":"external_commands","line_end":62,"severity":"medium","line_start":62},{"id":"external_commands:scripts/brewpage-run.sh:73:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"body=$(curl -s -A \"ClaudeCode/1.0\" https://brewpage.app/api/limits) || die \"limits request failed\"","category":"external_commands","line_end":73,"severity":"medium","line_start":73},{"id":"external_commands:scripts/brewpage-run.sh:103:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"printf 'RUN: %s\\nBYTES: %s\\n' \"$run\" \"$(wc -c < \"$file\" | tr -d ' ')\"","category":"external_commands","line_end":103,"severity":"medium","line_start":103},{"id":"external_commands:scripts/brewpage-run.sh:126:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"--text) need \"$#\" \"$1\"; text=\"$2\"; have_text=1; sources=$((sources + 1)); shift 2 ;;","category":"external_commands","line_end":126,"severity":"medium","line_start":126},{"id":"external_commands:scripts/brewpage-run.sh:127:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"--run) need \"$#\" \"$1\"; run=\"$2\"; sources=$((sources + 1)); shift 2 ;;","category":"external_commands","line_end":127,"severity":"medium","line_start":127},{"id":"external_commands:scripts/brewpage-run.sh:128:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"--path) need \"$#\" \"$1\"; path=\"$2\"; sources=$((sources + 1)); shift 2 ;;","category":"external_commands","line_end":128,"severity":"medium","line_start":128},{"id":"external_commands:scripts/brewpage-run.sh:180:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"response=$(bp_post \"https://brewpage.app/api/html?ns=$NS&ttl=$DAYS&format=markdown\" \\","category":"external_commands","line_end":181,"severity":"medium","line_start":180},{"id":"external_commands:scripts/brewpage-run.sh:186:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"response=$(bp_post \"https://brewpage.app/api/json?ns=$NS&ttl=$DAYS\" \\","category":"external_commands","line_end":187,"severity":"medium","line_start":186},{"id":"external_commands:scripts/brewpage-run.sh:191:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"response=$(bp_post \"https://brewpage.app/api/files?ns=$NS&ttl=$DAYS\" -F \"$(form_file file \"$path\")\")","category":"external_commands","line_end":191,"severity":"medium","line_start":191},{"id":"external_commands:scripts/brewpage-run.sh:197:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"manifest=$(node \"$HERE/publish.mjs\" pack --dir \"$path\" --out \"$archive\" ${ENTRY:+--entry \"$ENTRY\"}) ","category":"external_commands","line_end":197,"severity":"medium","line_start":197},{"id":"external_commands:scripts/brewpage-run.sh:202:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"manifest=$(node \"$HERE/publish.mjs\" inspect --zip \"$path\" ${ENTRY:+--entry \"$ENTRY\"}) || rc=$?","category":"external_commands","line_end":202,"severity":"medium","line_start":202},{"id":"external_commands:scripts/brewpage-run.sh:206:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"response=$(bp_post \"https://brewpage.app/api/sites?ns=$NS&ttl=$DAYS&entry=$(jq -nr --arg e \"$ENTRY\" ","category":"external_commands","line_end":206,"severity":"medium","line_start":206},{"id":"external_commands:scripts/brewpage-run.sh:207:shell-command-substitution","file":"scripts/brewpage-run.sh","pattern":"Shell command substitution","snippet":"-H \"User-Agent: ClaudeCode/1.0\" -F \"$(form_file archive \"$archive\")\") || die \"upload request failed\"","category":"external_commands","line_end":207,"severity":"medium","line_start":207},{"id":"network:scripts/brewpage-run.sh:73:hardcoded-url","file":"scripts/brewpage-run.sh","pattern":"Hardcoded URL","snippet":"body=$(curl -s -A \"ClaudeCode/1.0\" https://brewpage.app/api/limits) || die \"limits request failed\"","category":"network","line_end":73,"severity":"low","line_start":73},{"id":"network:scripts/brewpage-run.sh:180:hardcoded-url","file":"scripts/brewpage-run.sh","pattern":"Hardcoded URL","snippet":"response=$(bp_post \"https://brewpage.app/api/html?ns=$NS&ttl=$DAYS&format=markdown\" \\","category":"network","line_end":180,"severity":"low","line_start":180},{"id":"network:scripts/brewpage-run.sh:186:hardcoded-url","file":"scripts/brewpage-run.sh","pattern":"Hardcoded URL","snippet":"response=$(bp_post \"https://brewpage.app/api/json?ns=$NS&ttl=$DAYS\" \\","category":"network","line_end":186,"severity":"low","line_start":186},{"id":"network:scripts/brewpage-run.sh:191:hardcoded-url","file":"scripts/brewpage-run.sh","pattern":"Hardcoded URL","snippet":"response=$(bp_post \"https://brewpage.app/api/files?ns=$NS&ttl=$DAYS\" -F \"$(form_file file \"$path\")\")","category":"network","line_end":191,"severity":"low","line_start":191},{"id":"network:scripts/brewpage-run.sh:206:hardcoded-url","file":"scripts/brewpage-run.sh","pattern":"Hardcoded URL","snippet":"response=$(bp_post \"https://brewpage.app/api/sites?ns=$NS&ttl=$DAYS&entry=$(jq -nr --arg e \"$ENTRY\" ","category":"network","line_end":206,"severity":"low","line_start":206},{"id":"filesystem:scripts/brewpage-run.sh:62:standard-device-file-access","file":"scripts/brewpage-run.sh","pattern":"Standard device file access","snippet":"\"$(file --mime-type -b -- \"$abs\" 2>/dev/null || echo unknown)\"","category":"filesystem","line_end":62,"severity":"low","line_start":62},{"id":"filesystem:scripts/brewpage-run.sh:71:standard-device-file-access","file":"scripts/brewpage-run.sh","pattern":"Standard device file access","snippet":"command -v jq >/dev/null || die \"jq required\"","category":"filesystem","line_end":71,"severity":"low","line_start":71},{"id":"filesystem:scripts/brewpage-run.sh:77:standard-device-file-access","file":"scripts/brewpage-run.sh","pattern":"Standard device file access","snippet":"\"PATH_MAX_CHARS: \\($s.maxPathChars)\", \"PATH_MAX_BYTES: \\($s.maxPathBytes)\", \"NAME_MAX_BYTES: \\($s.ma","category":"filesystem","line_end":77,"severity":"low","line_start":77},{"id":"filesystem:scripts/brewpage-run.sh:134:standard-device-file-access","file":"scripts/brewpage-run.sh","pattern":"Standard device file access","snippet":"command -v python3 >/dev/null || die \"python3 required for secure history\"","category":"filesystem","line_end":134,"severity":"low","line_start":134},{"id":"filesystem:scripts/brewpage-run.sh:185:standard-device-file-access","file":"scripts/brewpage-run.sh","pattern":"Standard device file access","snippet":"jq empty \"$content\" 2>/dev/null || die \"payload is not valid JSON\"","category":"filesystem","line_end":185,"severity":"low","line_start":185},{"id":"blocker:scripts/brewpage-run.sh:152:system-reconnaissance","file":"scripts/brewpage-run.sh","pattern":"System reconnaissance","snippet":"local id pwmode=none","category":"blocker","line_end":152,"severity":"low","line_start":152},{"id":"blocker:scripts/brewpage-run.sh:170:system-reconnaissance","file":"scripts/brewpage-run.sh","pattern":"System reconnaissance","snippet":"[ -f \"$content\" ] || die \"run $id has no staged text\"","category":"blocker","line_end":170,"severity":"low","line_start":170},{"id":"blocker:scripts/brewpage-run.sh:185:system-reconnaissance","file":"scripts/brewpage-run.sh","pattern":"System reconnaissance","snippet":"jq empty \"$content\" 2>/dev/null || die \"payload is not valid JSON\"","category":"blocker","line_end":185,"severity":"low","line_start":185},{"id":"external_commands:scripts/history.py:55:python-subprocess-run","file":"scripts/history.py","pattern":"Python subprocess.run","snippet":"result = subprocess.run(['git', '-C', root] + arguments, stdout=subprocess.PIPE, stderr=subprocess.P","category":"external_commands","line_end":55,"severity":"high","line_start":55},{"id":"filesystem:scripts/history.py:33:python-file-write-append","file":"scripts/history.py","pattern":"Python file write/append","snippet":"with os.fdopen(fd, 'wb') as output:","category":"filesystem","line_end":33,"severity":"medium","line_start":33},{"id":"filesystem:scripts/history.py:41:python-os-file-operations","file":"scripts/history.py","pattern":"Python os file operations","snippet":"os.unlink(temporary, dir_fd=directory)","category":"filesystem","line_end":41,"severity":"medium","line_start":41},{"id":"env_access:scripts/history.py:55:python-environment-access","file":"scripts/history.py","pattern":"Python environment access","snippet":"result = subprocess.run(['git', '-C', root] + arguments, stdout=subprocess.PIPE, stderr=subprocess.P","category":"env_access","line_end":55,"severity":"low","line_start":55},{"id":"env_access:scripts/history.py:65:python-environment-access","file":"scripts/history.py","pattern":"Python environment access","snippet":"if os.path.lexists(os.path.join(parent, '.git')) or os.environ.get('GIT_DIR'):","category":"env_access","line_end":65,"severity":"low","line_start":65},{"id":"blocker:scripts/history.py:23:system-reconnaissance","file":"scripts/history.py","pattern":"System reconnaissance","snippet":"if not stat.S_ISREG(info.st_mode) or info.st_uid != os.getuid() or info.st_nlink != 1:","category":"blocker","line_end":23,"severity":"low","line_start":23},{"id":"blocker:scripts/history.py:82:system-reconnaissance","file":"scripts/history.py","pattern":"System reconnaissance","snippet":"raise ValueError('invalid history operation or destination')","category":"blocker","line_end":82,"severity":"low","line_start":82},{"id":"blocker:scripts/history.py:87:system-reconnaissance","file":"scripts/history.py","pattern":"System reconnaissance","snippet":"if info.st_uid != os.getuid() or info.st_mode & 0o022:","category":"blocker","line_end":87,"severity":"low","line_start":87},{"id":"blocker:scripts/history.py:99:system-reconnaissance","file":"scripts/history.py","pattern":"System reconnaissance","snippet":"if info.st_uid != os.getuid() or info.st_mode & 0o022:","category":"blocker","line_end":99,"severity":"low","line_start":99},{"id":"external_commands:scripts/publish.mjs:4:node-js-child-process-module","file":"scripts/publish.mjs","pattern":"Node.js child_process module","snippet":"import { spawnSync } from 'node:child_process';","category":"external_commands","line_end":4,"severity":"high","line_start":4},{"id":"external_commands:scripts/publish.mjs:153:synchronous-spawn","file":"scripts/publish.mjs","pattern":"Synchronous spawn","snippet":"const r = spawnSync('unzip', [flag, zipPath], { encoding: 'utf8', maxBuffer: LIST_MAX_BUFFER, timeou","category":"external_commands","line_end":153,"severity":"high","line_start":153},{"id":"external_commands:scripts/publish.mjs:205:synchronous-spawn","file":"scripts/publish.mjs","pattern":"Synchronous spawn","snippet":"const z = spawnSync('zip', ['-q', '-X', '-@', out], {","category":"external_commands","line_end":205,"severity":"high","line_start":205},{"id":"external_commands:scripts/publish.mjs:2:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** Offline SITE bundle build/verify: `pack --dir <abs-dir> --out <abs.zip> [--entry <name>]` | `ins","category":"external_commands","line_end":2,"severity":"medium","line_start":2},{"id":"external_commands:scripts/publish.mjs:26:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** True when a dot-named segment, outside the root `.well-known/`, keeps the path out of a site. */","category":"external_commands","line_end":26,"severity":"medium","line_start":26},{"id":"external_commands:scripts/publish.mjs:29:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** Extension-less files ship only inside the root `.well-known/` (e.g. `apple-app-site-association`","category":"external_commands","line_end":29,"severity":"medium","line_start":29},{"id":"external_commands:scripts/publish.mjs:30:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"const isWellKnownBare = (rel) => rel.startsWith(`${TRUSTED_DOT_DIR}/`) && extname(rel) === '';","category":"external_commands","line_end":30,"severity":"medium","line_start":30},{"id":"external_commands:scripts/publish.mjs:37:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** `unzip` stdout cap: Node's 1 MB default kills `-Z1` on a valid site with >1 MB of names (ENOBUFS","category":"external_commands","line_end":37,"severity":"medium","line_start":37},{"id":"external_commands:scripts/publish.mjs:71:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`FAILED: ${msg}`);","category":"external_commands","line_end":71,"severity":"medium","line_start":71},{"id":"external_commands:scripts/publish.mjs:81:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (!k.startsWith('--') || v === undefined) die(`bad argument near \"${k}\"`);","category":"external_commands","line_end":81,"severity":"medium","line_start":81},{"id":"external_commands:scripts/publish.mjs:90:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"die(`entry \"${entry}\" is not a plain relative file name`);","category":"external_commands","line_end":90,"severity":"medium","line_start":90},{"id":"external_commands:scripts/publish.mjs:120:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (!names.includes(requested)) die(`entry \"${requested}\" is not in the archive`);","category":"external_commands","line_end":120,"severity":"medium","line_start":120},{"id":"external_commands:scripts/publish.mjs:132:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** True when `p` is an executable regular file. */","category":"external_commands","line_end":132,"severity":"medium","line_start":132},{"id":"external_commands:scripts/publish.mjs:141:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (!dirs.some((dir) => exts.some((ext) => isExecutable(join(dir, bin + ext))))) die(`${bin} require","category":"external_commands","line_end":141,"severity":"medium","line_start":141},{"id":"external_commands:scripts/publish.mjs:146:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (r.status !== 0 && r.status !== null) return `${bin} exited ${r.status}`;","category":"external_commands","line_end":146,"severity":"medium","line_start":146},{"id":"external_commands:scripts/publish.mjs:147:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (r.error) return `${bin} failed (${r.error.code || r.error.message})`;","category":"external_commands","line_end":147,"severity":"medium","line_start":147},{"id":"external_commands:scripts/publish.mjs:148:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"return r.signal ? `${bin} killed by ${r.signal}` : '';","category":"external_commands","line_end":148,"severity":"medium","line_start":148},{"id":"external_commands:scripts/publish.mjs:151:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** One `unzip` run: { out }, or { why } telling a bad archive (non-zero exit) from a check that nev","category":"external_commands","line_end":151,"severity":"medium","line_start":151},{"id":"external_commands:scripts/publish.mjs:156:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"return why ? { why: `archive could not be checked: ${why}` } : { out: r.stdout || '' };","category":"external_commands","line_end":156,"severity":"medium","line_start":156},{"id":"external_commands:scripts/publish.mjs:159:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"/** `unzip -tq` then `unzip -Z1`: { names } sorted, directory entries dropped, or { why }. */","category":"external_commands","line_end":159,"severity":"medium","line_start":159},{"id":"external_commands:scripts/publish.mjs:173:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`ARCHIVE MANIFEST — ${basename(zipPath)}`);","category":"external_commands","line_end":173,"severity":"medium","line_start":173},{"id":"external_commands:scripts/publish.mjs:174:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"for (const n of names) console.log(`  ${n}`);","category":"external_commands","line_end":174,"severity":"medium","line_start":174},{"id":"external_commands:scripts/publish.mjs:175:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`FILES: ${names.length}`);","category":"external_commands","line_end":175,"severity":"medium","line_start":175},{"id":"external_commands:scripts/publish.mjs:176:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`BYTES: ${bytes}`);","category":"external_commands","line_end":176,"severity":"medium","line_start":176},{"id":"external_commands:scripts/publish.mjs:177:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`ENTRY: ${entry}`);","category":"external_commands","line_end":177,"severity":"medium","line_start":177},{"id":"external_commands:scripts/publish.mjs:178:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`SKIPPED: ${skipped.length}${skipped.length ? ` (${skipped.join(', ')})` : ''}`);","category":"external_commands","line_end":178,"severity":"medium","line_start":178},{"id":"external_commands:scripts/publish.mjs:179:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (unexpected.length) console.log(`UNEXPECTED: ${unexpected.join(', ')}`);","category":"external_commands","line_end":179,"severity":"medium","line_start":179},{"id":"external_commands:scripts/publish.mjs:181:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (flagged.length) console.log(`SENSITIVE: ${flagged.join(', ')}`);","category":"external_commands","line_end":181,"severity":"medium","line_start":181},{"id":"external_commands:scripts/publish.mjs:183:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"console.log(`RESULT: ${confirm ? 'confirm' : 'ok'}`);","category":"external_commands","line_end":183,"severity":"medium","line_start":183},{"id":"external_commands:scripts/publish.mjs:192:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (!existsSync(dir) || !statSync(dir).isDirectory()) die(`not a directory: ${dir}`);","category":"external_commands","line_end":192,"severity":"medium","line_start":192},{"id":"external_commands:scripts/publish.mjs:198:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (kept.length === 0) die(`no publishable files under ${dir} after the allowlist filter`);","category":"external_commands","line_end":198,"severity":"medium","line_start":198},{"id":"external_commands:scripts/publish.mjs:201:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"// BD-N03: `mktemp` leaves a 0-byte file that Info-ZIP reads as a corrupt","category":"external_commands","line_end":201,"severity":"medium","line_start":201},{"id":"external_commands:scripts/publish.mjs:206:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"cwd: dir, input: `${kept.join('\\n')}\\n`, encoding: 'utf8',","category":"external_commands","line_end":206,"severity":"medium","line_start":206},{"id":"external_commands:scripts/publish.mjs:212:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"die(`${zipWhy} — no archive produced`);","category":"external_commands","line_end":212,"severity":"medium","line_start":212},{"id":"external_commands:scripts/publish.mjs:224:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"die(`archive contents differ from the selected file set (in archive: ${listed.length}, selected: ${k","category":"external_commands","line_end":224,"severity":"medium","line_start":224},{"id":"external_commands:scripts/publish.mjs:232:ruby-shell-backtick-execution","file":"scripts/publish.mjs","pattern":"Ruby/shell backtick execution","snippet":"if (!existsSync(zipPath) || !statSync(zipPath).isFile()) die(`not a file: ${zipPath}`);","category":"external_commands","line_end":232,"severity":"medium","line_start":232},{"id":"filesystem:scripts/publish.mjs:5:synchronous-file-operations","file":"scripts/publish.mjs","pattern":"Synchronous file operations","snippet":"import { readdirSync, statSync, lstatSync, existsSync, rmSync, accessSync, constants, readFileSync }","category":"filesystem","line_end":5,"severity":"medium","line_start":5},{"id":"filesystem:scripts/publish.mjs:44:synchronous-file-operations","file":"scripts/publish.mjs","pattern":"Synchronous file operations","snippet":"const data = readFileSync(zipPath);","category":"filesystem","line_end":44,"severity":"medium","line_start":44},{"id":"filesystem:scripts/publish.mjs:110:hidden-file-access","file":"scripts/publish.mjs","pattern":"Hidden file access","snippet":"if (/[\\r\\n]/.test(rel)) { skipped.push(rel); continue; }","category":"filesystem","line_end":110,"severity":"medium","line_start":110},{"id":"filesystem:scripts/publish.mjs:201:temp-file-creation","file":"scripts/publish.mjs","pattern":"Temp file creation","snippet":"// BD-N03: `mktemp` leaves a 0-byte file that Info-ZIP reads as a corrupt","category":"filesystem","line_end":201,"severity":"low","line_start":201},{"id":"env_access:scripts/publish.mjs:139:environment-variable-access-dot-notation","file":"scripts/publish.mjs","pattern":"Environment variable access (dot notation)","snippet":"const exts = process.platform === 'win32' ? ['', ...(process.env.PATHEXT || '.EXE;.CMD;.BAT').split(","category":"env_access","line_end":139,"severity":"low","line_start":139},{"id":"env_access:scripts/publish.mjs:140:environment-variable-access-dot-notation","file":"scripts/publish.mjs","pattern":"Environment variable access (dot notation)","snippet":"const dirs = (process.env.PATH || '').split(delimiter).filter(Boolean);","category":"env_access","line_end":140,"severity":"low","line_start":140},{"id":"env_access:scripts/publish.mjs:139:environment-variable-object","file":"scripts/publish.mjs","pattern":"Environment variable object","snippet":"const exts = process.platform === 'win32' ? ['', ...(process.env.PATHEXT || '.EXE;.CMD;.BAT').split(","category":"env_access","line_end":139,"severity":"low","line_start":139},{"id":"env_access:scripts/publish.mjs:140:environment-variable-object","file":"scripts/publish.mjs","pattern":"Environment variable object","snippet":"const dirs = (process.env.PATH || '').split(delimiter).filter(Boolean);","category":"env_access","line_end":140,"severity":"low","line_start":140},{"id":"sensitive:scripts/publish.mjs:33:ssh-private-key-file","file":"scripts/publish.mjs","pattern":"SSH private key file","snippet":"const SENSITIVE_RE = /(^|\\/)(\\.env|id_rsa|id_ed25519)|secret|credential|password|token|\\.(pem|key|p1","category":"sensitive","line_end":33,"severity":"critical","line_start":33},{"id":"sensitive:scripts/publish.mjs:33:environment-file-access","file":"scripts/publish.mjs","pattern":"Environment file access","snippet":"const SENSITIVE_RE = /(^|\\/)(\\.env|id_rsa|id_ed25519)|secret|credential|password|token|\\.(pem|key|p1","category":"sensitive","line_end":33,"severity":"high","line_start":33},{"id":"sensitive:scripts/publish.mjs:139:environment-file-access","file":"scripts/publish.mjs","pattern":"Environment file access","snippet":"const exts = process.platform === 'win32' ? ['', ...(process.env.PATHEXT || '.EXE;.CMD;.BAT').split(","category":"sensitive","line_end":139,"severity":"high","line_start":139},{"id":"sensitive:scripts/publish.mjs:140:environment-file-access","file":"scripts/publish.mjs","pattern":"Environment file access","snippet":"const dirs = (process.env.PATH || '').split(delimiter).filter(Boolean);","category":"sensitive","line_end":140,"severity":"high","line_start":140},{"id":"sensitive:scripts/publish.mjs:24:sqlite-database-file","file":"scripts/publish.mjs","pattern":"SQLite database file","snippet":"const SYSTEM_RE = /^(__MACOSX|\\.Spotlight-V100|\\.Trashes|\\.fseventsd)\\/|(^|\\/)(\\.DS_Store|Thumbs\\.db","category":"sensitive","line_end":24,"severity":"medium","line_start":24},{"id":"blocker:scripts/publish.mjs:37:system-reconnaissance","file":"scripts/publish.mjs","pattern":"System reconnaissance","snippet":"/** `unzip` stdout cap: Node's 1 MB default kills `-Z1` on a valid site with >1 MB of names (ENOBUFS","category":"blocker","line_end":37,"severity":"low","line_start":37},{"id":"blocker:scripts/publish.mjs:48:system-reconnaissance","file":"scripts/publish.mjs","pattern":"System reconnaissance","snippet":"if (end < floor) return 'archive has no valid central directory';","category":"blocker","line_end":48,"severity":"low","line_start":48},{"id":"external_commands:SKILL.md:18:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Every shell step is ONE command of the exact shape in the fences below: the single `allowed-tools`","category":"external_commands","line_end":18,"severity":"medium","line_start":18},{"id":"external_commands:SKILL.md:21:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Fill each `'{...}'` slot with the raw value and write every `'` inside it as `'\\''`; nothing else ","category":"external_commands","line_end":21,"severity":"medium","line_start":21},{"id":"external_commands:SKILL.md:22:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"escaped. Never wrap a value in double quotes. An empty slot stays `''` (= omitted).","category":"external_commands","line_end":22,"severity":"medium","line_start":22},{"id":"external_commands:SKILL.md:23:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Never quote the script path, prefix or chain the command (`cd`, `VAR=...`, `;`, `&&`, `|`, `$(...)","category":"external_commands","line_end":23,"severity":"medium","line_start":23},{"id":"external_commands:SKILL.md:26:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"through `stage` (Step 6).","category":"external_commands","line_end":26,"severity":"medium","line_start":26},{"id":"external_commands:SKILL.md:27:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- The script prints one decisive line: `OK {url}` or `OK {url} | Files: N` (then any `NOTICE: ...` l","category":"external_commands","line_end":27,"severity":"medium","line_start":27},{"id":"external_commands:SKILL.md:28:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"what the server skipped or adjusted), `CONFIRM: ...` (exit 2, nothing uploaded) or `FAILED: ...` (se","category":"external_commands","line_end":28,"severity":"medium","line_start":28},{"id":"external_commands:SKILL.md:35:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Extract from `$ARGUMENTS`:","category":"external_commands","line_end":35,"severity":"medium","line_start":35},{"id":"external_commands:SKILL.md:36:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- `--ttl N` → TTL in days (default: `15`)","category":"external_commands","line_end":36,"severity":"medium","line_start":36},{"id":"external_commands:SKILL.md:37:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- `--entry <filename>` → entry file for SITE uploads (default: auto-detect)","category":"external_commands","line_end":37,"severity":"medium","line_start":37},{"id":"external_commands:SKILL.md:38:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- `--delivery-mode path|subdomain` → optional creation header; omitted means server defaults. Reject","category":"external_commands","line_end":38,"severity":"medium","line_start":38},{"id":"external_commands:SKILL.md:39:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Remaining text → `content_arg`: a path, or the exact text to publish. Fired by Claude mid-task, th","category":"external_commands","line_end":39,"severity":"medium","line_start":39},{"id":"external_commands:SKILL.md:44:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"A `content_arg` that names a path -> probe it (read-only; prints `TYPE:`, the absolute `PATH:` to us","category":"external_commands","line_end":44,"severity":"medium","line_start":44},{"id":"external_commands:SKILL.md:47:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":49,"severity":"medium","line_start":47},{"id":"external_commands:SKILL.md:49:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":51,"severity":"medium","line_start":49},{"id":"external_commands:SKILL.md:51:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| Input | Type | `publish` type + source | API |","category":"external_commands","line_end":53,"severity":"medium","line_start":51},{"id":"external_commands:SKILL.md:53:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `TYPE: site-dir` | SITE | `site-dir` + `--path` | `POST /api/sites` (ZIP built from the dir — prim","category":"external_commands","line_end":53,"severity":"medium","line_start":53},{"id":"external_commands:SKILL.md:54:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `TYPE: site-zip` (`.zip` file) | SITE | `site-zip` + `--path` | `POST /api/sites` (pre-built archi","category":"external_commands","line_end":54,"severity":"medium","line_start":54},{"id":"external_commands:SKILL.md:55:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `TYPE: file` or `TYPE: markdown` (any other file) | FILE | `file` + `--path` | `POST /api/files` (","category":"external_commands","line_end":55,"severity":"medium","line_start":55},{"id":"external_commands:SKILL.md:56:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| No path (`TYPE: none`), `content_arg` starts with `{` or `[` | JSON | `json` + `--text` | `POST /a","category":"external_commands","line_end":56,"severity":"medium","line_start":56},{"id":"external_commands:SKILL.md:57:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| Anything else | HTML | `html` + `--text` | `POST /api/html` (format=markdown) |","category":"external_commands","line_end":57,"severity":"medium","line_start":57},{"id":"external_commands:SKILL.md:59:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Mode rule: directory/ZIP → SITE. Single file → FILE. `POST /api/sites` accepts a multipart `archive=","category":"external_commands","line_end":59,"severity":"medium","line_start":59},{"id":"external_commands:SKILL.md:63:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"From the probe lines — SITE (dir): `HTML`, `SIZE_KB`, `ENTRY`. SITE (ZIP): `BYTES`, entry override. ","category":"external_commands","line_end":63,"severity":"medium","line_start":63},{"id":"external_commands:SKILL.md:66:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":69,"severity":"medium","line_start":66},{"id":"external_commands:SKILL.md:69:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":71,"severity":"medium","line_start":69},{"id":"external_commands:SKILL.md:71:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"For SITE (entry = server rule: `--entry` > root `index.html` > shallowest `.html`; another page → pa","category":"external_commands","line_end":71,"severity":"medium","line_start":71},{"id":"external_commands:SKILL.md:74:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- No `.html` file in the directory (`ENTRY: none`) → **FAIL** with an explicit error: \"No `.html` fo","category":"external_commands","line_end":74,"severity":"medium","line_start":74},{"id":"external_commands:SKILL.md:75:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- The directory looks like un-built sources (has `package.json` + `src/` but no top-level `.html`) →","category":"external_commands","line_end":75,"severity":"medium","line_start":75},{"id":"external_commands:SKILL.md:76:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":80,"severity":"medium","line_start":76},{"id":"external_commands:SKILL.md:80:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":82,"severity":"medium","line_start":80},{"id":"external_commands:SKILL.md:82:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"`ENTRY:` line is the entry `scripts/publish.mjs` resolved in the built archive.","category":"external_commands","line_end":82,"severity":"medium","line_start":82},{"id":"external_commands:SKILL.md:84:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**Site limits** (`GET https://brewpage.app/api/limits` returns the current ones): 25 MB per request;","category":"external_commands","line_end":86,"severity":"medium","line_start":84},{"id":"external_commands:SKILL.md:86:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"380 characters / 900 bytes, each file or folder name at most 200 bytes. A big site (`FILES` or `SIZE","category":"external_commands","line_end":86,"severity":"medium","line_start":86},{"id":"external_commands:SKILL.md:89:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":91,"severity":"medium","line_start":89},{"id":"external_commands:SKILL.md:91:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":92,"severity":"medium","line_start":91},{"id":"external_commands:SKILL.md:92:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Pre-checks, folder or ZIP: system files (`.DS_Store`, `__MACOSX/`, `Thumbs.db`) never count and are","category":"external_commands","line_end":92,"severity":"medium","line_start":92},{"id":"external_commands:SKILL.md:93:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"dropped; hidden files and folders are dropped too, except the root `.well-known/`; at least one `.ht","category":"external_commands","line_end":93,"severity":"medium","line_start":93},{"id":"external_commands:SKILL.md:100:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":110,"severity":"medium","line_start":100},{"id":"external_commands:SKILL.md:110:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":113,"severity":"medium","line_start":110},{"id":"external_commands:SKILL.md:113:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- File → topic/purpose of the file (e.g. `api-docs`, `login-page`, `report-q2`)","category":"external_commands","line_end":113,"severity":"medium","line_start":113},{"id":"external_commands:SKILL.md:114:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Text/HTML → main subject or title (e.g. `pricing`, `team-intro`, `changelog`)","category":"external_commands","line_end":114,"severity":"medium","line_start":114},{"id":"external_commands:SKILL.md:115:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- JSON → data type or schema name (e.g. `user-config`, `metrics`)","category":"external_commands","line_end":115,"severity":"medium","line_start":115},{"id":"external_commands:SKILL.md:119:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Resolution: explicit `2` or `4` → suggested slug | `1` → `public` | custom slug → validate it.","category":"external_commands","line_end":119,"severity":"medium","line_start":119},{"id":"external_commands:SKILL.md:126:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":135,"severity":"medium","line_start":126},{"id":"external_commands:SKILL.md:135:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":137,"severity":"medium","line_start":135},{"id":"external_commands:SKILL.md:137:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Resolution: explicit `1` or `3` → `{password_file}` = `''` (no password). `2` + an existing","category":"external_commands","line_end":137,"severity":"medium","line_start":137},{"id":"external_commands:SKILL.md:138:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"local file path → `{password_file}` = that absolute path: the script moves the bytes via private hea","category":"external_commands","line_end":145,"severity":"medium","line_start":138},{"id":"external_commands:SKILL.md:145:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"Delivery mode: NEW sites and non-public HTML pages (format `html`) get a Dedicated subdomain (an exp","category":"external_commands","line_end":145,"severity":"medium","line_start":145},{"id":"external_commands:SKILL.md:146:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"its subdomain and the response reports the mismatch); everything else defaults to Promotion (`path`)","category":"external_commands","line_end":147,"severity":"medium","line_start":146},{"id":"external_commands:SKILL.md:147:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"select `subdomain`, password-protected included. Send it only as `X-Delivery-Mode`, never in authore","category":"external_commands","line_end":147,"severity":"medium","line_start":147},{"id":"external_commands:SKILL.md:148:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"OLD or NEW winner may differ: keep its identity, cohort, mode and exact `link`. Missing/null OLD rou","category":"external_commands","line_end":157,"severity":"medium","line_start":148},{"id":"external_commands:SKILL.md:157:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `{ns}` | `^[a-z0-9-]{1,32}$` |","category":"external_commands","line_end":157,"severity":"medium","line_start":157},{"id":"external_commands:SKILL.md:158:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `{days}` | positive integer; `''` = 15 |","category":"external_commands","line_end":158,"severity":"medium","line_start":158},{"id":"external_commands:SKILL.md:159:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `{entry}` | plain relative file name, no `..`; `''` = auto-detect; sites only |","category":"external_commands","line_end":159,"severity":"medium","line_start":159},{"id":"external_commands:SKILL.md:160:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `{delivery_mode}` | `''`, `path` or `subdomain` |","category":"external_commands","line_end":160,"severity":"medium","line_start":160},{"id":"external_commands:SKILL.md:161:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `{password_file}` | `''` or an absolute path to an existing regular file |","category":"external_commands","line_end":161,"severity":"medium","line_start":161},{"id":"external_commands:SKILL.md:164:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"any run is touched, so staged text survives the retry. `{type}` comes from the Step 2 table.","category":"external_commands","line_end":166,"severity":"medium","line_start":164},{"id":"external_commands:SKILL.md:166:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**SITE, FILE** — `{path}` is the probe's `PATH:` — **EXECUTE** using Bash tool:","category":"external_commands","line_end":166,"severity":"medium","line_start":166},{"id":"external_commands:SKILL.md:167:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":169,"severity":"medium","line_start":167},{"id":"external_commands:SKILL.md:169:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":171,"severity":"medium","line_start":169},{"id":"external_commands:SKILL.md:171:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**HTML text, JSON** — `{content}` is the exact text or JSON, verbatim — **EXECUTE** using Bash tool:","category":"external_commands","line_end":172,"severity":"medium","line_start":171},{"id":"external_commands:SKILL.md:172:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":174,"severity":"medium","line_start":172},{"id":"external_commands:SKILL.md:174:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":177,"severity":"medium","line_start":174},{"id":"external_commands:SKILL.md:177:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"of at most 6,000 characters. The first `stage` call passes `--run ''` and prints `RUN: brewpage.XXXX","category":"external_commands","line_end":177,"severity":"medium","line_start":177},{"id":"external_commands:SKILL.md:180:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":182,"severity":"medium","line_start":180},{"id":"external_commands:SKILL.md:182:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":184,"severity":"medium","line_start":182},{"id":"external_commands:SKILL.md:184:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":186,"severity":"medium","line_start":184},{"id":"external_commands:SKILL.md:186:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":188,"severity":"medium","line_start":186},{"id":"external_commands:SKILL.md:188:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":190,"severity":"medium","line_start":188},{"id":"external_commands:SKILL.md:190:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":194,"severity":"medium","line_start":190},{"id":"external_commands:SKILL.md:194:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**Success** (the script printed `OK {url}`):","category":"external_commands","line_end":195,"severity":"medium","line_start":194},{"id":"external_commands:SKILL.md:195:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":199,"severity":"medium","line_start":195},{"id":"external_commands:SKILL.md:199:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":201,"severity":"medium","line_start":199},{"id":"external_commands:SKILL.md:201:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**Success for SITE** (the script printed `OK {url} | Files: {count}`):","category":"external_commands","line_end":202,"severity":"medium","line_start":201},{"id":"external_commands:SKILL.md:202:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":209,"severity":"medium","line_start":202},{"id":"external_commands:SKILL.md:209:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":214,"severity":"medium","line_start":209},{"id":"external_commands:SKILL.md:214:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"For a private (non-`public`) namespace, append one short line after the link (skip if the reply must","category":"external_commands","line_end":214,"severity":"medium","line_start":214},{"id":"external_commands:SKILL.md:218:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**Needs confirmation** (the script printed `CONFIRM: ...`, exit 2; nothing uploaded): show the manif","category":"external_commands","line_end":219,"severity":"medium","line_start":218},{"id":"external_commands:SKILL.md:219:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"lines, name the flagged entries, ask ONE `AskUserQuestion` (publish anyway / cancel). Publish anyway","category":"external_commands","line_end":220,"severity":"medium","line_start":219},{"id":"external_commands:SKILL.md:220:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"re-run the identical command with ` --confirmed` appended. Cancel or no answer -> stop: the script a","category":"external_commands","line_end":223,"severity":"medium","line_start":220},{"id":"external_commands:SKILL.md:223:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"**Error** (the script printed `FAILED: ...`):","category":"external_commands","line_end":224,"severity":"medium","line_start":223},{"id":"external_commands:SKILL.md:224:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":226,"severity":"medium","line_start":224},{"id":"external_commands:SKILL.md:226:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":232,"severity":"medium","line_start":226},{"id":"external_commands:SKILL.md:232:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| 422 | No servable file left (every file has an unsupported or missing extension) | Add the `.html`","category":"external_commands","line_end":242,"severity":"medium","line_start":232},{"id":"external_commands:SKILL.md:242:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Scripts: `scripts/brewpage-run.sh` (the only entry), `scripts/brewpage-lib.sh` (sourced helpers), ","category":"external_commands","line_end":242,"severity":"medium","line_start":242},{"id":"external_commands:SKILL.md:243:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- **`format` is a query param**: `/api/html` reads only `?format=` from the URL; a body `format` key","category":"external_commands","line_end":243,"severity":"medium","line_start":243},{"id":"external_commands:SKILL.md:244:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- History: `<project-root>/.claude/brewpage-history.md` (root: `CLAUDE_PROJECT_DIR` → git toplevel →","category":"external_commands","line_end":244,"severity":"medium","line_start":244},{"id":"external_commands:SKILL.md:245:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Run dirs: private `brewpage.XXXXXX` under `$TMPDIR` (else `/tmp`), outside the protected `.claude/","category":"external_commands","line_end":245,"severity":"medium","line_start":245},{"id":"external_commands:SKILL.md:246:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Permissions: model-invocable, so `allowed-tools` holds one scoped Bash rule that matches every ste","category":"external_commands","line_end":247,"severity":"medium","line_start":246},{"id":"external_commands:SKILL.md:247:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- TTL default is `15` days; stored `createdAt`/`expiresAt` are authoritative: a deduplicated winner ","category":"external_commands","line_end":247,"severity":"medium","line_start":247},{"id":"external_commands:SKILL.md:248:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Use returned `ownerLink` and stored identity metadata for owner API operations; never parse NEW ro","category":"external_commands","line_end":249,"severity":"medium","line_start":248},{"id":"external_commands:SKILL.md:249:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- To **update a published site**, `PUT` the replacement bundle to its apex owner API with `X-Owner-T","category":"external_commands","line_end":249,"severity":"medium","line_start":249},{"id":"external_commands:SKILL.md:250:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Owner-only `GET`/`PATCH /api/{type}/{ns}/{id}/hosting` supports `html|files|json|kv|sites` with `X","category":"external_commands","line_end":250,"severity":"medium","line_start":250},{"id":"external_commands:SKILL.md:251:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- NEW password-protected links stay clean: never generate or append `?p=`. API requests use `X-Passw","category":"external_commands","line_end":251,"severity":"medium","line_start":251},{"id":"external_commands:SKILL.md:252:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- **SITE bundles are allowlisted**: the directory build drops dot-entries (`.env`, `.git/`, `.DS_Sto","category":"external_commands","line_end":252,"severity":"medium","line_start":252},{"id":"external_commands:SKILL.md:253:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"- Preserve `.link` exactly: NEW subdomain roots retain `/`; OLD links retain their existing form. Ne","category":"external_commands","line_end":253,"severity":"medium","line_start":253},{"id":"external_commands:SKILL.md:23:shell-command-substitution","file":"SKILL.md","pattern":"Shell command substitution","snippet":"- Never quote the script path, prefix or chain the command (`cd`, `VAR=...`, `;`, `&&`, `|`, `$(...)","category":"external_commands","line_end":23,"severity":"medium","line_start":23},{"id":"external_commands:SKILL.md:23:template-literal-with-command-substitution","file":"SKILL.md","pattern":"Template literal with command substitution","snippet":"- Never quote the script path, prefix or chain the command (`cd`, `VAR=...`, `;`, `&&`, `|`, `$(...)","category":"external_commands","line_end":23,"severity":"medium","line_start":23},{"id":"network:SKILL.md:84:hardcoded-url","file":"SKILL.md","pattern":"Hardcoded URL","snippet":"**Site limits** (`GET https://brewpage.app/api/limits` returns the current ones): 25 MB per request;","category":"network","line_end":84,"severity":"low","line_start":84},{"id":"network:SKILL.md:198:hardcoded-url","file":"SKILL.md","pattern":"Hardcoded URL","snippet":"Optional: sign in free (Google or any email) at https://account.brewpage.app to manage publications ","category":"network","line_end":198,"severity":"low","line_start":198},{"id":"network:SKILL.md:206:hardcoded-url","file":"SKILL.md","pattern":"Hardcoded URL","snippet":"Optional: sign in free (Google or any email) at https://account.brewpage.app to manage publications ","category":"network","line_end":206,"severity":"low","line_start":206},{"id":"network:SKILL.md:262:hardcoded-url","file":"SKILL.md","pattern":"Hardcoded URL","snippet":"| **[brewpage.app](https://brewpage.app)** | Free instant hosting — HTML, JSON, files, sites, KV. No","category":"network","line_end":262,"severity":"low","line_start":262},{"id":"network:SKILL.md:263:hardcoded-url","file":"SKILL.md","pattern":"Hardcoded URL","snippet":"| **[brewcode](https://github.com/kochetkov-ma/claude-brewcode)** | Claude Code plugin suite — skill","category":"network","line_end":263,"severity":"low","line_start":263},{"id":"filesystem:SKILL.md:197:hidden-file-access","file":"SKILL.md","pattern":"Hidden file access","snippet":"Owner token saved to <project-root>/.claude/brewpage-history.md (mode 600, git-ignored)","category":"filesystem","line_end":197,"severity":"medium","line_start":197},{"id":"filesystem:SKILL.md:205:hidden-file-access","file":"SKILL.md","pattern":"Hidden file access","snippet":"Owner token saved to <project-root>/.claude/brewpage-history.md (mode 600, git-ignored)","category":"filesystem","line_end":205,"severity":"medium","line_start":205},{"id":"filesystem:SKILL.md:244:hidden-file-access","file":"SKILL.md","pattern":"Hidden file access","snippet":"- History: `<project-root>/.claude/brewpage-history.md` (root: `CLAUDE_PROJECT_DIR` → git toplevel →","category":"filesystem","line_end":244,"severity":"medium","line_start":244},{"id":"sensitive:SKILL.md:252:environment-file-access","file":"SKILL.md","pattern":"Environment file access","snippet":"- **SITE bundles are allowlisted**: the directory build drops dot-entries (`.env`, `.git/`, `.DS_Sto","category":"sensitive","line_end":252,"severity":"high","line_start":252},{"id":"sensitive:SKILL.md:92:sqlite-database-file","file":"SKILL.md","pattern":"SQLite database file","snippet":"Pre-checks, folder or ZIP: system files (`.DS_Store`, `__MACOSX/`, `Thumbs.db`) never count and are","category":"sensitive","line_end":92,"severity":"medium","line_start":92},{"id":"sensitive:SKILL.md:252:sqlite-database-file","file":"SKILL.md","pattern":"SQLite database file","snippet":"- **SITE bundles are allowlisted**: the directory build drops dot-entries (`.env`, `.git/`, `.DS_Sto","category":"sensitive","line_end":252,"severity":"medium","line_start":252},{"id":"blocker:SKILL.md:235:system-reconnaissance","file":"SKILL.md","pattern":"System reconnaissance","snippet":"Unstorable metadata (tags, names, control characters) is stored as the closest valid value with a no","category":"blocker","line_end":235,"severity":"low","line_start":235},{"id":"obfuscation:scripts/brewpage-lib.sh:102:heuristic-very-high-entropy-string-6-03-bits-lik","file":"scripts/brewpage-lib.sh","pattern":"[HEURISTIC] Very high entropy string (6.03 bits) - likely encoded/encrypted payload","snippet":" in *[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.]*) echo ","category":"obfuscation","line_end":102,"severity":"high","line_start":102}],"finding_verdicts":[{"id":"network:LICENSE:3:hardcoded-url","reason":"The GitHub URL identifies the copyright holder in the MIT license. It does not initiate network access.","verdict":"false_positive","confidence":1},{"id":"network:README.md:115:hardcoded-url","reason":"This documented deletion example sends an owner token only to the stated Brewpage API. It is not an automatic request or unrelated destination.","verdict":"false_positive","confidence":0.99},{"id":"network:README.md:125:hardcoded-url","reason":"The GitHub URL appears in an explicit plugin installation example. The skill scripts do not execute this installation.","verdict":"false_positive","confidence":0.99},{"id":"sensitive:README.md:68:environment-file-access","reason":"The paragraph explains that directory packaging excludes .env and other hidden entries. It does not instruct reading environment files.","verdict":"false_positive","confidence":1},{"id":"sensitive:README.md:68:sqlite-database-file","reason":"Thumbs.db is named as excluded operating-system metadata. No SQLite database is opened or uploaded by this documentation.","verdict":"false_positive","confidence":1},{"id":"blocker:README.md:89:system-reconnaissance","reason":"The paragraph describes preserving returned publication identity and routing metadata. It contains no host enumeration or system reconnaissance.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:51:ruby-shell-backtick-execution","reason":"Backticks are literal Markdown in a single-quoted HEADER heredoc. The documented curl example is not executed.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:52:ruby-shell-backtick-execution","reason":"The PUT example is literal history-file documentation in a quoted heredoc. Its backticks do not perform command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:62:ruby-shell-backtick-execution","reason":"Backticks occur inside a single-quoted printf format for Markdown history. Values are passed as data, not evaluated as shell commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:65:ruby-shell-backtick-execution","reason":"The single-quoted printf format writes literal Markdown code spans. The shell does not execute these backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:166:ruby-shell-backtick-execution","reason":"Backticks surround set -- in a shell comment. Comments cannot execute this text.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:187:ruby-shell-backtick-execution","reason":"The word site is formatted with backticks in a comment. It is not executable shell syntax.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:8:shell-command-substitution","reason":"The substitution canonicalizes an explicitly supplied directory using quoted cd and pwd. Directory contents are not evaluated as shell code.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:9:shell-command-substitution","reason":"Quoted cd and pwd resolve HOME for a profile-directory comparison. This does not execute environment-variable contents.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:10:shell-command-substitution","reason":"Quoted directory resolution compares CLAUDE_CONFIG_DIR with a candidate profile path. It does not read credentials or execute that path as code.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:21:shell-command-substitution","reason":"The fixed git rev-parse command locates the project root for local history. No user-controlled shell source is constructed.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:32:shell-command-substitution","reason":"dirname receives a quoted directory value while walking ancestors. The resulting path remains data.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:37:shell-command-substitution","reason":"This invokes the local bp_project_root helper and captures its directory output. It does not evaluate returned text as commands.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:47:shell-command-substitution","reason":"dirname resolves the bundled history.py script location. Quoted arguments select secure local history initialization rather than arbitrary shell execution.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:63:shell-command-substitution","reason":"Fixed date formatting and dirname locate the bundled history writer. Publication fields travel through printf data arguments, not shell evaluation.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:66:shell-command-substitution","reason":"The substitutions generate a timestamp and resolve the bundled history writer. Variable values remain quoted printf arguments.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:105:shell-command-substitution","reason":"find checks mode 0700 on the selected run directory without descending. This enforces private temporary storage rather than executing directory contents.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:190:shell-command-substitution","reason":"A fixed jq expression extracts the response link from JSON. Response bytes are supplied through printf, not evaluated as shell code.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:192:shell-command-substitution","reason":"The local error-formatting helper parses the response with jq. It does not run commands contained in the response.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:199:shell-command-substitution","reason":"jq extracts the returned owner token for restricted local history. The token is not executed or printed by this substitution.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:201:shell-command-substitution","reason":"A fixed jq filter reads ownerLink metadata for history. This does not make a request to the returned URL.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:202:shell-command-substitution","reason":"jq selects publication identity and expiry metadata into a compact JSON value. The output is stored as data without shell evaluation.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:204:shell-command-substitution","reason":"jq reads fileCount for the publication result. No commands are constructed from that field.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:229:shell-command-substitution","reason":"sed extracts the manifest entry as data for the upload parameter. The upload URL separately URI-encodes that entry.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-lib.sh:62:template-literal-with-command-substitution","reason":"This is a single-quoted shell printf format with literal Markdown backticks. Nearby substitutions provide data arguments, not interpolated executable source.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-lib.sh:65:template-literal-with-command-substitution","reason":"The backticks belong to a single-quoted Markdown format string. The shell does not evaluate formatted history contents.","verdict":"false_positive","confidence":1},{"id":"network:scripts/brewpage-lib.sh:51:hardcoded-url","reason":"The Brewpage API URL is literal deletion documentation inside a quoted heredoc. This line performs no network request.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:84:path-traversal-sequence","reason":"Traversal sequences appear in a case arm that rejects unsafe entry values. Site processing also validates relative entry segments in publish.mjs.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:10:hidden-file-access","reason":"The .claude comparison identifies profile configuration directories so they are not selected as project roots. It does not read hidden credentials.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:14:hidden-file-access","reason":"This comment documents project-root discovery using .git and .claude directory markers. It does not access file contents.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:28:hidden-file-access","reason":"Directory existence checks identify a project root. The operation does not collect hidden-file contents.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:38:hidden-file-access","reason":"This assigns the documented local owner-token history path. history.py enforces restrictive permissions, rejects unsafe links, and prevents tracked history.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:8:standard-device-file-access","reason":"The /dev/null redirection suppresses directory-resolution errors. It does not access a sensitive device.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:9:standard-device-file-access","reason":"The /dev/null redirection discards errors from the HOME path comparison. No device data is read.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:10:standard-device-file-access","reason":"The config-directory comparison redirects errors to /dev/null. This is ordinary output suppression.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:21:standard-device-file-access","reason":"Git project-root detection discards stderr through /dev/null. It does not read protected device contents.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:46:standard-device-file-access","reason":"command -v checks for Python and discards its path output. /dev/null is used only as an output sink.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:132:standard-device-file-access","reason":"command -v checks that jq exists and suppresses its output. This does not access sensitive devices.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:133:standard-device-file-access","reason":"Password validation discards jq output and errors to avoid exposing password bytes. The source is an explicitly selected local password file.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:148:standard-device-file-access","reason":"The jq dependency check redirects ordinary command output to /dev/null. It is not a sensitive file operation.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:160:standard-device-file-access","reason":"jq revalidates copied password bytes and writes a header under umask 077. Error suppression avoids exposing the password.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-lib.sh:183:standard-device-file-access","reason":"The error-response parser suppresses jq diagnostics through /dev/null. This redirection reads no device contents.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:196:standard-device-file-access","reason":"A Boolean jq ownership check discards its output and errors. /dev/null is only a sink for diagnostics.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:212:standard-device-file-access","reason":"The notice parser suppresses jq errors and normalizes control characters. The device reference is only stderr redirection.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-lib.sh:93:temp-file-creation","reason":"mktemp creates an unpredictable run directory under umask 077. Subsequent checks require ownership, mode 0700, and a non-symlink directory.","verdict":"false_positive","confidence":0.99},{"id":"blocker:scripts/brewpage-lib.sh:100:system-reconnaissance","reason":"This branch rejects malformed publish-run identifiers. It does not inspect host identity.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-lib.sh:102:system-reconnaissance","reason":"The explicit ASCII character list rejects unsafe run identifiers. It performs no system reconnaissance.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-lib.sh:125:system-reconnaissance","reason":"The jq expression creates a password header only after length and control-character checks. It does not query system information.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-lib.sh:127:system-reconnaissance","reason":"This comment specifies validation for the user-selected password file. No reconnaissance command is present.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-lib.sh:215:network-reconnaissance","reason":"The comment describes the local archive validation gate. It performs no network probing.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-run.sh:6:shell-command-substitution","reason":"Quoted dirname, cd, and pwd resolve the installed script directory. The resulting path locates bundled helpers rather than executing supplied text.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:25:shell-command-substitution","reason":"The local bp_prepare helper creates a private temporary directory. Its generated path is captured as data.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:47:shell-command-substitution","reason":"Quoted cd and pwd canonicalize the user-selected site directory. No path text is evaluated as shell source.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:49:shell-command-substitution","reason":"The fixed find and text-processing pipeline enumerates HTML candidates in the selected directory. Filenames remain output data.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:52:shell-command-substitution","reason":"Fixed awk, sort, sed, and cut commands select the shallowest HTML candidate. Filename text is never evaluated as commands.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:55:shell-command-substitution","reason":"The substitutions count files and HTML candidates for pre-publication statistics. They use fixed commands and quoted input paths.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:56:shell-command-substitution","reason":"du and cut measure the selected directory for a read-only probe. The quoted directory argument is not executable source.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:58:shell-command-substitution","reason":"dirname, basename, cd, and pwd construct an absolute source filename. Quoting preserves the value as data.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:61:shell-command-substitution","reason":"wc and tr report the selected file size. The source path is quoted and not interpreted as code.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:62:shell-command-substitution","reason":"file probes MIME type with a quoted argument after --. This read-only metadata operation does not execute the selected file.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:73:shell-command-substitution","reason":"The fixed HTTPS GET retrieves Brewpage upload limits. It sends no content, password, or owner token.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:103:shell-command-substitution","reason":"wc counts staged text bytes in the validated private run directory. The result is printed as a statistic.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:126:shell-command-substitution","reason":"The matched syntax is arithmetic expansion incrementing a source counter. It is not command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-run.sh:127:shell-command-substitution","reason":"The expression increments an internally initialized numeric counter while parsing flags. No external command is invoked.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-run.sh:128:shell-command-substitution","reason":"This is arithmetic expansion for counting input sources. The path argument is stored separately and not evaluated.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/brewpage-run.sh:180:shell-command-substitution","reason":"The fixed HTML endpoint receives the selected content through a jq-generated payload. Namespace and TTL are validated before URL construction.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:186:shell-command-substitution","reason":"The fixed JSON endpoint receives the selected payload after jq validation. The response is captured as data, not executed.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:191:shell-command-substitution","reason":"The file upload uses the stated Brewpage endpoint and escapes curl multipart filename syntax. This is the requested publishing function, not shell injection.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/brewpage-run.sh:197:shell-command-substitution","reason":"The bundled Node helper builds and verifies a site archive using quoted arguments. Its exit status gates upload; no shell source is synthesized.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/brewpage-run.sh:202:shell-command-substitution","reason":"The bundled Node helper inspects the supplied archive through quoted arguments. The separate source-change race is recorded as a semantic finding.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/brewpage-run.sh:206:shell-command-substitution","reason":"The intended HTTPS site upload validates namespace and TTL, and URI-encodes the entry value with jq. It does not evaluate entry text as code.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/brewpage-run.sh:207:shell-command-substitution","reason":"form_file escapes the archive filename for curl multipart syntax. The separate mutable-archive risk is documented as a semantic finding.","verdict":"false_positive","confidence":0.98},{"id":"network:scripts/brewpage-run.sh:73:hardcoded-url","reason":"The HTTPS URL is the advertised service limits endpoint. The GET contains no private payload or credentials.","verdict":"false_positive","confidence":0.99},{"id":"network:scripts/brewpage-run.sh:180:hardcoded-url","reason":"The URL is the advertised HTML publication endpoint. Uploading user-selected content there is the disclosed purpose of the skill.","verdict":"false_positive","confidence":0.99},{"id":"network:scripts/brewpage-run.sh:186:hardcoded-url","reason":"The fixed HTTPS JSON endpoint belongs to the advertised publication service. There is no unrelated destination or covert credential transfer.","verdict":"false_positive","confidence":0.99},{"id":"network:scripts/brewpage-run.sh:191:hardcoded-url","reason":"The fixed HTTPS files endpoint uploads the selected local file. The workflow requires explicit publication choices before invoking this operation.","verdict":"false_positive","confidence":0.99},{"id":"network:scripts/brewpage-run.sh:206:hardcoded-url","reason":"The URL is the stated site publication API, with validated query values. Its presence is expected for a publishing skill.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/brewpage-run.sh:62:standard-device-file-access","reason":"MIME detection suppresses file-command errors through /dev/null. This does not read a sensitive device.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-run.sh:71:standard-device-file-access","reason":"command -v checks the jq dependency and discards output. /dev/null is used only as a sink.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-run.sh:77:standard-device-file-access","reason":"The limits parser discards jq diagnostics through /dev/null. The matched line reports path-size limits rather than accessing device data.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-run.sh:134:standard-device-file-access","reason":"The Python dependency check redirects ordinary output to /dev/null. No protected file or device is read.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/brewpage-run.sh:185:standard-device-file-access","reason":"JSON validation suppresses parser diagnostics. /dev/null is an error-output sink, not a data source.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-run.sh:152:system-reconnaissance","reason":"id is a local variable holding a publish-run identifier. The line does not invoke the system id command.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-run.sh:170:system-reconnaissance","reason":"This checks whether the selected run has staged text and reports failure otherwise. It performs no host enumeration.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/brewpage-run.sh:185:system-reconnaissance","reason":"jq checks the selected payload for valid JSON. It does not inspect system identity or configuration.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/history.py:55:python-subprocess-run","reason":"subprocess.run invokes fixed Git safety checks through an argument list without shell=True. These checks prevent tracked or ineffectively ignored owner-token history.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/history.py:33:python-file-write-append","reason":"The writer uses an exclusively created, non-symlink temporary file and atomic replacement. Ownership, link-count, destination, and permission checks protect local token history.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/history.py:41:python-os-file-operations","reason":"unlink removes only the random temporary filename within an already opened directory. It cleans up the atomic local history write.","verdict":"false_positive","confidence":0.99},{"id":"env_access:scripts/history.py:55:python-environment-access","reason":"The environment is inherited by fixed local Git safety checks, with LC_ALL set to C. No environment values are serialized or sent over the network.","verdict":"false_positive","confidence":0.98},{"id":"env_access:scripts/history.py:65:python-environment-access","reason":"GIT_DIR is checked only to detect a repository when Git is unavailable. The code then refuses unsafe history handling.","verdict":"false_positive","confidence":0.99},{"id":"blocker:scripts/history.py:23:system-reconnaissance","reason":"File type, ownership, and link-count checks reject unsafe history files. getuid is used for access protection, not host profiling.","verdict":"false_positive","confidence":0.99},{"id":"blocker:scripts/history.py:82:system-reconnaissance","reason":"The exception rejects history operations or destinations outside an explicit allowlist. It is input validation, not reconnaissance.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/history.py:87:system-reconnaissance","reason":"The workspace ownership and mode check rejects directories writable by other users. This protects stored owner tokens.","verdict":"false_positive","confidence":0.99},{"id":"blocker:scripts/history.py:99:system-reconnaissance","reason":"Directory ownership and write-permission checks secure the history path. They do not collect unrelated system information.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/publish.mjs:4:node-js-child-process-module","reason":"spawnSync is imported for fixed zip and unzip commands used in site packaging. The reviewed calls use argument arrays without a shell.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/publish.mjs:153:synchronous-spawn","reason":"unzip receives fixed inspection flags and a separate archive-path argument. Checks have a ten-second timeout and bounded output, with no shell interpolation.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/publish.mjs:205:synchronous-spawn","reason":"zip receives fixed flags and an output path through an argument array. Selected filenames are passed on stdin, not assembled into shell commands.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/publish.mjs:2:ruby-shell-backtick-execution","reason":"The backticks format usage examples inside a JavaScript block comment. They cannot execute commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:26:ruby-shell-backtick-execution","reason":"The .well-known reference is backtick-formatted comment text. It performs no execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:29:ruby-shell-backtick-execution","reason":"Backticks format example filenames in a comment. No Ruby or shell evaluation occurs.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:30:ruby-shell-backtick-execution","reason":"This JavaScript template literal builds a prefix for a string comparison. It is not a shell command.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:37:ruby-shell-backtick-execution","reason":"The backticks format unzip flags in a documentation comment. The comment is not executed.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:71:ruby-shell-backtick-execution","reason":"A JavaScript template literal formats an error message for console.log. Interpolated text is not evaluated as shell source.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:81:ruby-shell-backtick-execution","reason":"The template literal formats an invalid-argument error. No shell or dynamic JavaScript evaluation is involved.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:90:ruby-shell-backtick-execution","reason":"This template literal reports rejection of an unsafe entry value. It does not execute the rejected value.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:120:ruby-shell-backtick-execution","reason":"The template literal produces an error when the requested entry is absent. It is string formatting, not command execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:132:ruby-shell-backtick-execution","reason":"Backticks surround a parameter name in a JavaScript comment. No execution is possible from that text.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:141:ruby-shell-backtick-execution","reason":"The template literal names a missing dependency in an error message. Executable discovery only checks filesystem metadata.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:146:ruby-shell-backtick-execution","reason":"The template literal formats a child-process exit status. It does not launch another process.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:147:ruby-shell-backtick-execution","reason":"The template literal formats an existing process error. Its contents remain a string.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:148:ruby-shell-backtick-execution","reason":"The template literal reports a child-process signal. No shell evaluates this returned string.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:151:ruby-shell-backtick-execution","reason":"Backticks identify unzip in a function documentation comment. The text is not executed.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:156:ruby-shell-backtick-execution","reason":"The template literal creates an archive-check error message. It does not evaluate its interpolated diagnostic as code.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:159:ruby-shell-backtick-execution","reason":"The backticks format unzip command names in a comment. Actual process execution is separately implemented with argument arrays.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:173:ruby-shell-backtick-execution","reason":"A JavaScript template literal prints the archive basename in a manifest heading. It is not shell execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:174:ruby-shell-backtick-execution","reason":"console.log prints each archive name through ordinary JavaScript string interpolation. Filenames are not executed.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:175:ruby-shell-backtick-execution","reason":"The template literal prints a numeric file count. No shell command is present.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:176:ruby-shell-backtick-execution","reason":"The template literal prints the archive byte count. This is plain manifest output.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:177:ruby-shell-backtick-execution","reason":"The template literal prints the resolved entry filename. It is not passed to a shell evaluator.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:178:ruby-shell-backtick-execution","reason":"Nested JavaScript template literals format skipped filenames as text. Neither literal performs shell command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:179:ruby-shell-backtick-execution","reason":"This template literal prints unexpected archive entries for human review. It does not execute those names.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:181:ruby-shell-backtick-execution","reason":"The template literal lists sensitive-looking filenames for confirmation. It does not read or execute their contents.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:183:ruby-shell-backtick-execution","reason":"The template literal prints a fixed confirm or ok result marker. No dynamic command execution occurs.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:192:ruby-shell-backtick-execution","reason":"The template literal reports an invalid directory argument. Its value is formatted as text, not evaluated.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:198:ruby-shell-backtick-execution","reason":"The template literal formats a failure when the allowlist selects no files. It executes no commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:201:ruby-shell-backtick-execution","reason":"Backticks format mktemp in a source comment about empty archives. The comment cannot invoke mktemp.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:206:ruby-shell-backtick-execution","reason":"The JavaScript template literal builds newline-separated filenames for zip stdin. It is not evaluated as shell source.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:scripts/publish.mjs:212:ruby-shell-backtick-execution","reason":"The template literal formats an archive-generation failure message. No diagnostic text is executed.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:224:ruby-shell-backtick-execution","reason":"The template literal reports a mismatch between expected and archived filenames. It is a defensive error message, not execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:scripts/publish.mjs:232:ruby-shell-backtick-execution","reason":"The template literal reports a missing archive file. The path is used as text rather than executable code.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/publish.mjs:5:synchronous-file-operations","reason":"The imports support local site enumeration, bounded archive inspection, and cleanup of generated archives. Importing filesystem APIs is not itself unsafe.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:scripts/publish.mjs:44:synchronous-file-operations","reason":"The selected archive is read to inspect its central directory after a size check. The separate mutable-source race is recorded as a semantic finding.","verdict":"false_positive","confidence":0.98},{"id":"filesystem:scripts/publish.mjs:110:hidden-file-access","reason":"The regular expression skips filenames containing carriage returns or newlines. This line neither reads hidden files nor accesses credentials.","verdict":"false_positive","confidence":1},{"id":"filesystem:scripts/publish.mjs:201:temp-file-creation","reason":"The matched mktemp reference is a comment explaining archive generation. It does not create a temporary file.","verdict":"false_positive","confidence":1},{"id":"env_access:scripts/publish.mjs:139:environment-variable-access-dot-notation","reason":"PATHEXT is consulted only for Windows executable suffix discovery. No secret environment value is collected or transmitted.","verdict":"false_positive","confidence":0.99},{"id":"env_access:scripts/publish.mjs:140:environment-variable-access-dot-notation","reason":"PATH is split to check whether required archive tools exist. This local dependency lookup does not exfiltrate environment contents.","verdict":"false_positive","confidence":0.99},{"id":"env_access:scripts/publish.mjs:139:environment-variable-object","reason":"The code accesses only PATHEXT for executable lookup, not the entire environment. It does not read an environment file.","verdict":"false_positive","confidence":0.99},{"id":"env_access:scripts/publish.mjs:140:environment-variable-object","reason":"The code reads PATH for local tool discovery. It does not enumerate or upload environment variables.","verdict":"false_positive","confidence":0.99},{"id":"sensitive:scripts/publish.mjs:33:ssh-private-key-file","reason":"id_rsa and id_ed25519 are filename patterns that trigger human confirmation. The regular expression does not open SSH private keys.","verdict":"false_positive","confidence":1},{"id":"sensitive:scripts/publish.mjs:33:environment-file-access","reason":"The .env string belongs to a sensitive-filename detector. It flags matching archive entries rather than discovering or reading environment files.","verdict":"false_positive","confidence":1},{"id":"sensitive:scripts/publish.mjs:139:environment-file-access","reason":"process.env.PATHEXT reads a process variable for tool lookup. It does not access a .env file.","verdict":"false_positive","confidence":1},{"id":"sensitive:scripts/publish.mjs:140:environment-file-access","reason":"process.env.PATH reads executable search directories. No environment file is opened.","verdict":"false_positive","confidence":1},{"id":"sensitive:scripts/publish.mjs:24:sqlite-database-file","reason":"Thumbs.db appears in a regular expression identifying system metadata. No SQLite API or database-content access is present.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/publish.mjs:37:system-reconnaissance","reason":"The comment explains the output buffer limit for unzip filename listings. It contains no reconnaissance operation.","verdict":"false_positive","confidence":1},{"id":"blocker:scripts/publish.mjs:48:system-reconnaissance","reason":"This returns an error for an archive without a valid central directory. It is archive validation, not system discovery.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:18:ruby-shell-backtick-execution","reason":"Markdown backticks name the declared allowed-tools rule. The text describes scoped invocation syntax, not executable backticks or audit approval.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:SKILL.md:21:ruby-shell-backtick-execution","reason":"Markdown code spans explain single-quote escaping for command arguments. They are documentation, not commands executed by backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:22:ruby-shell-backtick-execution","reason":"The code span documents an empty single-quoted argument. It performs no command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:23:ruby-shell-backtick-execution","reason":"Backticks list shell constructs the workflow prohibits. The prose does not execute those constructs.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:26:ruby-shell-backtick-execution","reason":"The code span names the stage subcommand for long text. It is explanatory Markdown.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:27:ruby-shell-backtick-execution","reason":"The backticks format expected success and notice output. No shell execution occurs from these examples.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:28:ruby-shell-backtick-execution","reason":"Markdown code spans document confirmation and failure messages. They are not executable shell substitutions.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:35:ruby-shell-backtick-execution","reason":"The code span names the skill argument placeholder. It does not evaluate that placeholder as shell source.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:36:ruby-shell-backtick-execution","reason":"Backticks document the TTL flag and its default value. No command is run by this line.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:37:ruby-shell-backtick-execution","reason":"The Markdown code span documents the optional entry flag. It is not shell evaluation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:38:ruby-shell-backtick-execution","reason":"The code span documents accepted delivery modes and requires rejection of invalid values. It performs no execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:39:ruby-shell-backtick-execution","reason":"The code span names the content argument in parsing instructions. It is documentation, not command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:44:ruby-shell-backtick-execution","reason":"Markdown code spans label the input and read-only probe output fields. They are not executable backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:47:ruby-shell-backtick-execution","reason":"This is a Markdown fence opening a read-only probe example. The matched backticks are formatting delimiters.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:49:ruby-shell-backtick-execution","reason":"The backticks close the documented probe command block. They are Markdown syntax rather than a shell command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:51:ruby-shell-backtick-execution","reason":"The code span labels a content-routing table column. It is not command execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:53:ruby-shell-backtick-execution","reason":"Table code spans map a directory probe result to the site upload API. They document the expected publishing workflow.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:54:ruby-shell-backtick-execution","reason":"Table code spans describe ZIP input routing. The Markdown does not execute the displayed tokens.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:55:ruby-shell-backtick-execution","reason":"The table describes local-file routing through the files API. Backticks format values rather than invoke commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:56:ruby-shell-backtick-execution","reason":"Code spans describe JSON detection and routing. No shell evaluates this table text.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:57:ruby-shell-backtick-execution","reason":"The table documents text publication through the HTML endpoint. Its backticks are Markdown formatting.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:59:ruby-shell-backtick-execution","reason":"Code spans describe multipart fields and the site endpoint. They do not execute a shell command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:63:ruby-shell-backtick-execution","reason":"The backticks label probe statistics such as size and MIME type. They are ordinary documentation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:66:ruby-shell-backtick-execution","reason":"This fence opens a plain-text publication-statistics example. It is not executable shell syntax.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:69:ruby-shell-backtick-execution","reason":"The Markdown fence closes the statistics example. No command substitution occurs.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:71:ruby-shell-backtick-execution","reason":"The code spans explain entry selection and explicit failure when no entry exists. They are not executable backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:74:ruby-shell-backtick-execution","reason":"Code spans identify the missing-HTML guard and its probe marker. The instruction prevents publishing unbuilt content.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:75:ruby-shell-backtick-execution","reason":"Code spans name source markers and suggested build-output directories. The prose requests review rather than executing directory names.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:76:ruby-shell-backtick-execution","reason":"The fence opens a plain-text site-statistics example. The backticks are Markdown delimiters.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:80:ruby-shell-backtick-execution","reason":"The fence closes the site-statistics example. It does not invoke a command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:82:ruby-shell-backtick-execution","reason":"Code spans identify the manifest entry marker and bundled packaging helper. They are documentation references.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:84:ruby-shell-backtick-execution","reason":"The code span documents a read-only limits endpoint on the advertised service. Markdown backticks do not execute the request.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:86:ruby-shell-backtick-execution","reason":"Backticks name file-count and size output fields used for limit checks. They contain no executable command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:89:ruby-shell-backtick-execution","reason":"This fence opens the documented limits command example. The delimiter itself is not shell execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:91:ruby-shell-backtick-execution","reason":"The fence closes the read-only limits command example. It is Markdown formatting.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:92:ruby-shell-backtick-execution","reason":"Code spans list system metadata excluded from publication. They do not access the listed files.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:93:ruby-shell-backtick-execution","reason":"Code spans document the .well-known exception and HTML requirement. They do not execute file or directory names.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:100:ruby-shell-backtick-execution","reason":"The fence opens the user-facing namespace question. It is a text example, not a shell command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:110:ruby-shell-backtick-execution","reason":"This fence closes the namespace-choice text. No backtick execution exists.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:113:ruby-shell-backtick-execution","reason":"The code spans show example namespace slugs based on file topics. They are not commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:114:ruby-shell-backtick-execution","reason":"The backticks format example text-publication slugs. This is naming guidance, not execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:115:ruby-shell-backtick-execution","reason":"The code spans show JSON publication slug examples. They are plain documentation values.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:119:ruby-shell-backtick-execution","reason":"Code spans label explicit namespace responses and the public option. They are consent-resolution documentation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:126:ruby-shell-backtick-execution","reason":"The fence opens a password-choice question. It does not execute anything.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:135:ruby-shell-backtick-execution","reason":"The fence closes the password-choice text. These backticks are Markdown delimiters.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:137:ruby-shell-backtick-execution","reason":"The code spans describe explicit password-choice resolution and an empty argument. They do not contain executable substitutions.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:138:ruby-shell-backtick-execution","reason":"The code span names the selected password-file slot. The surrounding prose requires private header-file transport rather than inline secrets.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:145:ruby-shell-backtick-execution","reason":"The code spans label namespace and HTML-format values in routing documentation. They are not executable backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:146:ruby-shell-backtick-execution","reason":"The backticks format path and subdomain delivery-mode values. They are ordinary text labels.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:147:ruby-shell-backtick-execution","reason":"Code spans name the delivery-mode header and a valid value. The prose limits where routing metadata may be sent.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:148:ruby-shell-backtick-execution","reason":"The code span names the returned link field. It instructs preserving server metadata, not executing it.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:157:ruby-shell-backtick-execution","reason":"The code spans document a namespace slot and validation expression. They do not invoke a regex or shell as source.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:158:ruby-shell-backtick-execution","reason":"The table documents the days slot and empty default. Backticks are formatting only.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:159:ruby-shell-backtick-execution","reason":"The table documents rejection of traversal in the entry slot. It is validation guidance, not command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:160:ruby-shell-backtick-execution","reason":"Code spans list accepted delivery-mode values. The text performs no execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:161:ruby-shell-backtick-execution","reason":"The table documents the password-file slot as an explicit path or empty choice. It does not read a password.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:164:ruby-shell-backtick-execution","reason":"The code span names the content-type slot selected by the routing table. It is documentation, not shell evaluation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:166:ruby-shell-backtick-execution","reason":"Code spans specify that uploads use the probed source path. The text describes the declared publishing operation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:167:ruby-shell-backtick-execution","reason":"The fence opens the bundled publish-command example. The backticks themselves are formatting delimiters.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:169:ruby-shell-backtick-execution","reason":"The fence closes the file or site publishing example. It is not executable backtick syntax.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:171:ruby-shell-backtick-execution","reason":"The code span names the exact text-content placeholder. It does not execute that content.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:172:ruby-shell-backtick-execution","reason":"The fence opens the inline text or JSON publishing example. Markdown delimiters do not perform command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:174:ruby-shell-backtick-execution","reason":"The fence closes the inline publishing example. These backticks are documentation syntax.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:177:ruby-shell-backtick-execution","reason":"Code spans document staging a long payload and receiving a generated run identifier. They do not execute the displayed identifier.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:180:ruby-shell-backtick-execution","reason":"The fence opens a staging-command example. It is not shell backtick execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:182:ruby-shell-backtick-execution","reason":"The fence closes the staging-command example. No command is invoked by the delimiter.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:184:ruby-shell-backtick-execution","reason":"The fence opens the staged-payload publishing example. The matched backticks are Markdown formatting.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:186:ruby-shell-backtick-execution","reason":"The fence closes the staged-payload publishing example. It does not execute a command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:188:ruby-shell-backtick-execution","reason":"The fence opens a cleanup example for a specific run identifier. It is documentation syntax, not command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:190:ruby-shell-backtick-execution","reason":"The fence closes the run-cleanup example. The delimiter itself is not executable.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:194:ruby-shell-backtick-execution","reason":"The code span documents the expected success marker. No shell evaluates that example output.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:195:ruby-shell-backtick-execution","reason":"The fence opens a user-facing success-output example. It is plain text formatting.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:199:ruby-shell-backtick-execution","reason":"The fence closes the success-output example. It performs no shell execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:201:ruby-shell-backtick-execution","reason":"The code span documents a successful site publication marker. It does not execute the returned URL.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:202:ruby-shell-backtick-execution","reason":"The fence opens the site-success output example. It is not a command substitution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:209:ruby-shell-backtick-execution","reason":"The fence closes the site-success output example. It is Markdown syntax only.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:214:ruby-shell-backtick-execution","reason":"Code spans distinguish private namespaces from public publication. The prose explains discoverability and does not execute either value.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:218:ruby-shell-backtick-execution","reason":"The code span documents the confirmation-required output marker. The workflow stops and asks the user before proceeding.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:219:ruby-shell-backtick-execution","reason":"The code span names the user-question tool for flagged entries. It is consent guidance, not shell execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:220:ruby-shell-backtick-execution","reason":"The code span documents the --confirmed flag after user approval. It does not execute the flag through backticks.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:223:ruby-shell-backtick-execution","reason":"The code span labels the failure-output marker. It is documentation rather than a command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:224:ruby-shell-backtick-execution","reason":"The fence opens a plain-text error-output example. It cannot invoke shell backtick execution.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:226:ruby-shell-backtick-execution","reason":"The fence closes the error-output example. It is Markdown formatting.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:232:ruby-shell-backtick-execution","reason":"The code span names the HTML extension in troubleshooting guidance. It is not an executable command.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:242:ruby-shell-backtick-execution","reason":"Code spans list bundled scripts and required runtime tools. They are documentation references, not shell substitutions.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:243:ruby-shell-backtick-execution","reason":"The code spans document placement of the format query parameter. They do not execute the named fields.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:244:ruby-shell-backtick-execution","reason":"Code spans describe local history location, permissions, and Git exclusion. Actual writes are handled by the protected history helper.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:245:ruby-shell-backtick-execution","reason":"Code spans document private temporary run directories and cleanup ownership. They are not shell evaluation.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:246:ruby-shell-backtick-execution","reason":"The code span names the declared scoped allowed-tools rule. The text describes runtime permissions, not authority to bypass this audit.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:SKILL.md:247:ruby-shell-backtick-execution","reason":"Code spans document TTL defaults and authoritative expiry metadata. They contain no executable shell source.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:248:ruby-shell-backtick-execution","reason":"The code span names ownerLink metadata for later management. It does not automatically execute a request to that value.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:249:ruby-shell-backtick-execution","reason":"Code spans document owner-authenticated site replacement and token confidentiality. No update command is executed by these backticks.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:SKILL.md:250:ruby-shell-backtick-execution","reason":"Code spans document owner-authenticated hosting operations. The entry script does not implement automatic management requests from this prose.","verdict":"false_positive","confidence":0.99},{"id":"external_commands:SKILL.md:251:ruby-shell-backtick-execution","reason":"Code spans prohibit password query strings and name the password header. The guidance reduces credential exposure.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:252:ruby-shell-backtick-execution","reason":"Code spans explain exclusion filters and confirmation checks for site bundles. The Markdown does not execute filenames or archive commands.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:253:ruby-shell-backtick-execution","reason":"Code spans document preserving the returned link and trailing slash. No dynamic command execution is requested.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:23:shell-command-substitution","reason":"The literal $(...) appears in a list of prohibited command shapes. It is explanatory Markdown, not evaluated shell code.","verdict":"false_positive","confidence":1},{"id":"external_commands:SKILL.md:23:template-literal-with-command-substitution","reason":"Markdown backticks quote shell syntax that the instructions prohibit. There is no executable template containing a substitution.","verdict":"false_positive","confidence":1},{"id":"network:SKILL.md:84:hardcoded-url","reason":"The documented HTTPS endpoint returns current service upload limits. It is an expected read-only request to the advertised host.","verdict":"false_positive","confidence":0.99},{"id":"network:SKILL.md:198:hardcoded-url","reason":"The account URL is an optional user-facing management link. The workflow explicitly says sign-in is not required and sends no credentials there automatically.","verdict":"false_positive","confidence":0.99},{"id":"network:SKILL.md:206:hardcoded-url","reason":"The link appears in optional site-publication success text. It does not initiate an account login or transmit local owner tokens.","verdict":"false_positive","confidence":0.99},{"id":"network:SKILL.md:262:hardcoded-url","reason":"The URL links to the advertised hosting service in a credits table. It is not a covert network destination.","verdict":"false_positive","confidence":1},{"id":"network:SKILL.md:263:hardcoded-url","reason":"The GitHub URL identifies the upstream plugin suite in a credits table. This line performs no network operation.","verdict":"false_positive","confidence":1},{"id":"filesystem:SKILL.md:197:hidden-file-access","reason":"The output example reports local owner-token history with mode 600 and Git exclusion. It does not request reading unrelated hidden files.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:SKILL.md:205:hidden-file-access","reason":"The site-success example names the documented private history file. The implementation protects writes with ownership, link, permission, and Git checks.","verdict":"false_positive","confidence":0.99},{"id":"filesystem:SKILL.md:244:hidden-file-access","reason":"The note describes project-local history placement and restrictive permissions. It does not instruct collecting profile credentials.","verdict":"false_positive","confidence":0.99},{"id":"sensitive:SKILL.md:252:environment-file-access","reason":"The .env reference documents dropping hidden directory entries from site bundles. It does not request reading environment-file contents.","verdict":"false_positive","confidence":1},{"id":"sensitive:SKILL.md:92:sqlite-database-file","reason":"Thumbs.db is listed as operating-system metadata excluded from publication. No SQLite database access is described.","verdict":"false_positive","confidence":1},{"id":"sensitive:SKILL.md:252:sqlite-database-file","reason":"Thumbs.db appears in documentation of excluded system files. This is not a database-reading operation.","verdict":"false_positive","confidence":1},{"id":"blocker:SKILL.md:235:system-reconnaissance","reason":"The paragraph describes normalization of unstorable publication metadata. It contains no system-discovery command.","verdict":"false_positive","confidence":1},{"id":"obfuscation:scripts/brewpage-lib.sh:102:heuristic-very-high-entropy-string-6-03-bits-lik","reason":"The high-entropy string is an explicit ASCII character allowlist for run identifiers. It is neither an encoded payload nor decoded into executable content.","verdict":"false_positive","confidence":1}],"semantic_findings":[{"title":"Archive Validation Is Not Bound to Uploaded Bytes","severity":"medium","locations":[{"file":"scripts/brewpage-run.sh","line_end":207,"line_start":200}],"confidence":0.94,"description":"The supplied ZIP is inspected, then curl reopens its original path for upload. A concurrent writer can replace its contents between steps, bypassing archive checks and sensitive-entry confirmation.","confidence_reasoning":"The site-zip branch assigns the original path to archive and passes that path separately to inspection and curl. Exploitation requires concurrent source write access."}],"subject_marketplace_commit_sha":"d0890ce2c604a2d107a7fc44f7c85f24a072fbe5","subject_content_hash":"b15355ed8c401f28f23f94bd44f7148b639bc6979c8955de9f937244b1dcad27","subject_tree_hash":"f3abe8d11326c4a5221e89a47b3f1b04ea2be77e9acacec3ace7ba2bb4467262","subject_plugin_path":"skills/kochetkov-ma/brewpage-publish","audit_payload_hash":"e09230caf2dc8c6c9e90ad06f5af86e8","confirmed_risk_level":"medium","scanner_version":"3.0.0","policy_version":"skillstore-security-audit-policy-v1","subject":{"marketplaceCommitSha":"d0890ce2c604a2d107a7fc44f7c85f24a072fbe5","contentHash":"b15355ed8c401f28f23f94bd44f7148b639bc6979c8955de9f937244b1dcad27","treeHash":"f3abe8d11326c4a5221e89a47b3f1b04ea2be77e9acacec3ace7ba2bb4467262","pluginPath":"skills/kochetkov-ma/brewpage-publish","auditPayloadHash":"e09230caf2dc8c6c9e90ad06f5af86e8"},"scannerVersion":"3.0.0","policyVersion":"skillstore-security-audit-policy-v1"},"auditTranslation":null,"localization":{"requestedLocale":"en","contentLocale":"en","availableLocales":["en"],"fallbackToEnglish":false},"attestation":{"availability":"issued","url":"/api/skills/kochetkov-ma-brewpage-publish/audits/7/attestation","status":"superseded"},"trust":{"publicState":"public","auditState":"complete","auditCurrentness":null,"confirmedRiskLevel":"medium","confirmedFindingCount":1,"capabilityReviewCount":0,"needsReviewCount":0,"falsePositiveCount":0,"agentAutoInstallPolicy":"allowed","manualInstallPolicy":"allowed","artifactSignatureState":"available","attestationState":"superseded","verificationState":"not_verified"},"isLatest":false}}