Harden tag mode tool permissions against prompt injection (#1002)
Two defenses for tag mode where an attacker with repo write access could craft a prompt injection payload in an issue/PR to gain RCE on the Actions runner: 1. git-push wrapper (H1 #3556799) The Bash(git\ push:*) rule permitted arbitrary flags and remotes, including combinations that execute shell commands locally. Replaced with scripts/git-push.sh which allowlists exactly 'origin <ref>' with no flags, validates the ref via check-ref-format. Same pattern as scripts/gh.sh. 2. acceptEdits instead of blanket Write/Edit (Asana 1213310082312048) Edit/MultiEdit/Write in allowedTools granted write access to the whole runner filesystem (~/.bashrc etc). Removed from allowedTools and set --permission-mode acceptEdits, which auto-accepts edits inside cwd ($GITHUB_WORKSPACE) and denies outside. Headless SDK has no prompt handler so 'ask' becomes deny. Also: - Noted that create-prompt/index.ts exports ALLOWED_TOOLS env var that nothing reads. The live path is modes/tag/index.ts. Mirrored the fix in both so the file the H1 report likely points to stays in sync. - Updated prompt text (3 callsites) to reference the wrapper. - Updated tests (4 prompt-content asserts, 7 tool-list asserts).
This commit is contained in:
1 parent
5d0cc745cd
commit
f956510b1a
5 files changed
+84
-42
No files matched your search
+11
-8
@@ -114,16 +114,17 @@ export async function prepareTagMode({
|
||||
tool.startsWith("mcp__github_"),
|
||||
);
|
||||
|
||||
// Build claude_args for tag mode with required tools
|
||||
// Tag mode REQUIRES these tools to function properly
|
||||
const gitPushWrapper = `${process.env.GITHUB_ACTION_PATH}/scripts/git-push.sh`;
|
||||
|
||||
// Build claude_args for tag mode with required tools.
|
||||
// Edit/MultiEdit/Write are intentionally omitted: acceptEdits permission mode (set below)
|
||||
// auto-allows file edits inside $GITHUB_WORKSPACE and denies writes outside (e.g. ~/.bashrc).
|
||||
// Listing them here would grant blanket write access to the whole runner (Asana 1213310082312048).
|
||||
const tagModeTools = [
|
||||
"Edit",
|
||||
"MultiEdit",
|
||||
"Glob",
|
||||
"Grep",
|
||||
"LS",
|
||||
"Read",
|
||||
"Write",
|
||||
"mcp__github_comment__update_claude_comment",
|
||||
"mcp__github_ci__get_ci_status",
|
||||
"mcp__github_ci__get_workflow_run_details",
|
||||
@@ -137,7 +138,7 @@ export async function prepareTagMode({
|
||||
tagModeTools.push(
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git push:*)",
|
||||
`Bash(${gitPushWrapper}:*)`,
|
||||
"Bash(git status:*)",
|
||||
"Bash(git diff:*)",
|
||||
"Bash(git log:*)",
|
||||
@@ -171,8 +172,10 @@ export async function prepareTagMode({
|
||||
const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''");
|
||||
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
||||
|
||||
// Add required tools for tag mode
|
||||
claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`;
|
||||
// Add required tools for tag mode.
|
||||
// acceptEdits: file edits auto-allowed inside cwd ($GITHUB_WORKSPACE), denied outside.
|
||||
// Headless SDK has no prompt handler, so anything that falls through to "ask" is denied.
|
||||
claudeArgs += ` --permission-mode acceptEdits --allowedTools "${tagModeTools.join(",")}"`;
|
||||
|
||||
// Append user's claude_args (which may have more --mcp-config flags)
|
||||
if (userClaudeArgs) {
|
||||
|
||||
Reference in new issue
Block a user