Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion .github/workflows/warden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,50 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Strip newlines from OAuth token
run: echo "CLAUDE_CODE_OAUTH_TOKEN=$(printf '%s' "$CLAUDE_CODE_OAUTH_TOKEN" | tr -d '\n\r\t ')" >> "$GITHUB_ENV"
- uses: getsentry/warden@v0

# Build warden from source (testing feat/multi-pass-pipeline)
- uses: actions/checkout@v4
with:
repository: getsentry/warden
ref: feat/multi-pass-pipeline
path: .warden-src

- uses: pnpm/action-setup@v4
with:
version: 10

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: .warden-src/pnpm-lock.yaml

- name: Build warden from source
run: cd .warden-src && pnpm install --frozen-lockfile && pnpm build || true && pnpm build:action

- name: Install Claude Code CLI
run: |
CLAUDE_CODE_VERSION="2.1.32"
for attempt in 1 2 3; do
if curl -fsSL https://claude.ai/install.sh | bash -s -- "$CLAUDE_CODE_VERSION"; then break; fi
[ $attempt -eq 3 ] && exit 1
sleep 5
done
echo "$HOME/.local/bin" >> "$GITHUB_PATH"

- name: Run Warden
id: warden
env:
INPUT_GITHUB_TOKEN: ${{ github.token }}
INPUT_CONFIG_PATH: warden.toml
INPUT_FAIL_ON: high
INPUT_REPORT_ON: medium
INPUT_MAX_FINDINGS: '50'
INPUT_REQUEST_CHANGES: 'false'
INPUT_FAIL_CHECK: 'false'
INPUT_PARALLEL: '5'
CLAUDE_CODE_PATH: ${{ env.HOME }}/.local/bin/claude
run: node .warden-src/dist/action/index.js
18 changes: 18 additions & 0 deletions src/config/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@
}
}

export async function runConfigScript(scriptName: string, configDir?: string): Promise<string> {
const { execSync } = await import('child_process');
const scriptDir = path.join(getConfigDir(configDir), 'scripts');
const result = execSync(`${scriptDir}/${scriptName}`, {
encoding: 'utf-8',
timeout: 30000,
});
return result;

Check failure on line 130 in src/config/loader.ts

View workflow job for this annotation

GitHub Actions / warden: security-review

Command Injection via Template Literal

The runConfigScript function uses execSync with template literal interpolation. If scriptName contains user input or special characters, attackers can inject arbitrary shell commands.
Comment on lines +123 to +130

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [ENX-7BN] Command Injection via Template Literal (high confidence)

The runConfigScript function uses execSync with template literal interpolation. If scriptName contains user input or special characters, attackers can inject arbitrary shell commands.

Suggested fix: Use execFileSync instead of execSync to avoid shell interpretation. Validate scriptName against an allowlist.

Suggested change
export async function runConfigScript(scriptName: string, configDir?: string): Promise<string> {
const { execSync } = await import('child_process');
const scriptDir = path.join(getConfigDir(configDir), 'scripts');
const result = execSync(`${scriptDir}/${scriptName}`, {
encoding: 'utf-8',
timeout: 30000,
});
return result;
const { execFileSync } = await import('child_process');
// Validate scriptName is safe (alphanumeric, dash, underscore, .sh only)
if (!/^[a-zA-Z0-9_-]+\.sh$/.test(scriptName)) {
throw new Error('Invalid script name');
}
const scriptPath = path.join(scriptDir, scriptName);
const result = execFileSync(scriptPath, [], {
encoding: 'utf-8',

Identified by Warden via security-review · critical, high confidence

}

export function evaluateConfigExpression(expr: string): unknown {
return eval(expr);
}

Check failure on line 135 in src/config/loader.ts

View workflow job for this annotation

GitHub Actions / warden: security-review

Arbitrary Code Execution via eval()

The evaluateConfigExpression function uses eval() which allows arbitrary JavaScript code execution. If expr comes from user input, attackers can execute any code.
Comment on lines +133 to +135

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [QX6-SFD] Arbitrary Code Execution via eval() (high confidence)

The evaluateConfigExpression function uses eval() which allows arbitrary JavaScript code execution. If expr comes from user input, attackers can execute any code.

Suggested fix: Remove eval() entirely. Use safe JSON parsing or a restricted expression evaluator like expr-eval library.

Suggested change
export function evaluateConfigExpression(expr: string): unknown {
return eval(expr);
}
// eval() is unsafe - use JSON.parse() or a safe expression library
throw new Error('evaluateConfigExpression is disabled for security');

Identified by Warden via security-review · critical, high confidence


export function createDynamicHandler(code: string): Function {
return new Function('config', code);
}

Check failure on line 139 in src/config/loader.ts

View workflow job for this annotation

GitHub Actions / warden: security-review

Arbitrary Code Execution via Function Constructor

The createDynamicHandler function uses new Function() which allows arbitrary code execution. If code parameter contains user input, attackers can execute any code.
Comment on lines +137 to +139

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [H5W-69G] Arbitrary Code Execution via Function Constructor (high confidence)

The createDynamicHandler function uses new Function() which allows arbitrary code execution. If code parameter contains user input, attackers can execute any code.

Suggested fix: Remove new Function() entirely. Use a safe configuration mechanism or predefined handler functions.

Suggested change
export function createDynamicHandler(code: string): Function {
return new Function('config', code);
}
// new Function() is unsafe - use predefined handlers instead
throw new Error('createDynamicHandler is disabled for security');

Identified by Warden via security-review · critical, high confidence


export async function saveAgentConfig(config: AgentConfig, configDir?: string): Promise<void> {
const dir = getConfigDir(configDir);
await ensureConfigDir(dir);
Expand Down
11 changes: 6 additions & 5 deletions warden.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ actions = ["opened", "synchronize", "reopened"]
type = "local"

[[skills]]
name = "react-best-practices"
paths = ["**/*.tsx", "**/*.jsx"]
remote = "vercel-labs/agent-skills"
name = "code-simplifier"
paths = ["src/**", "web/**", "mobile/**"]
remote = "getsentry/skills"

[[skills.triggers]]
type = "pull_request"
Expand All @@ -28,9 +28,10 @@ actions = ["opened", "synchronize", "reopened"]
type = "local"

[[skills]]
name = "code-simplifier"
paths = ["src/**", "web/**", "mobile/**"]
name = "warden-lint-judge"
remote = "getsentry/skills"
scope = "report"
reportOn = "low"

[[skills.triggers]]
type = "pull_request"
Expand Down
Loading