Rules / GL085
GL085 AI coding agent with approvals disabled or untrusted prompt input
Severity: error when approvals are disabled and the prompt contains user-controlled text, or the job runs on merge request pipelines; warn otherwise
OWASP: CICD-SEC-4 – Poisoned Pipeline Execution
CWE: CWE-1427 – Improper Neutralization of Input Used for LLM Prompting
Risk
Pipelines increasingly run coding agents for review, triage or autofix. An agent decides which commands to run based on what it reads, so text in its prompt or in the files it inspects works like instructions. Two settings turn that into code execution for whoever writes that text:
- Approvals disabled. The agent runs any tool, shell commands included, without confirmation.
- Untrusted text in the prompt. A merge request title or description, a commit message, a branch name, or the comment that triggered a GitLab Duo flow (
AI_FLOW_INPUT,AI_FLOW_CONTEXT). Quoting stops shell injection, but not prompt injection.
Together, and in any job that merge request pipelines reach, anyone who can open a merge request gets command execution with the job's token and secrets.
What glsec checks
Every script line (script:, before_script:, after_script:, default:, hooks:pre_get_sources_script, run: steps) that invokes an agent CLI in command position, also through npx/bunx/pnpm dlx, a package scope (@anthropic-ai/claude-code), a path, or after VAR=value assignments. Lines joined with a trailing \ are read as one command. Only the agent's own command counts, up to the next |, ; or &.
| Agent | Approval-bypass flags |
|---|---|
Claude Code (claude) |
--dangerously-skip-permissions, --permission-mode bypassPermissions, --allowedTools granting Bash without a command pattern or as Bash(*) |
Codex CLI (codex) |
--dangerously-bypass-approvals-and-sandbox (alias --yolo), --sandbox / -s danger-full-access |
Gemini CLI (gemini) |
--yolo, -y, --approval-mode yolo |
Copilot CLI (copilot) |
--allow-all-tools, --allow-all, --yolo |
The untrusted-prompt check needs a prompt argument (-p, --print, --prompt, -i, codex exec) and one of the GL002 user-controlled variables or AI_FLOW_INPUT / AI_FLOW_CONTEXT in the same command.
| Condition | Severity |
|---|---|
| Approvals disabled and untrusted prompt text | error |
Approvals disabled in a job that runs on merge request pipelines (its rules:/only: name them, or it has none and workflow:rules admit them) |
error |
| Approvals disabled, any other job | warn |
| Untrusted prompt text only | warn |
Trigger example
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
ai-review:
script:
- 'claude -p "Review this merge request: $CI_MERGE_REQUEST_TITLE" --dangerously-skip-permissions'
Safe alternative
ai-review:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- claude -p "Review the diff in mr.diff and write findings to review.md" --allowedTools "Read,Grep,Bash(git diff:*)"
- Grant only the tools the job needs. Restrict shell access to specific commands (
Bash(git diff:*)). - Keep untrusted text out of the prompt. Write it to a file the agent reads as data.
- Give the job a read-only token, and no deploy or publish secrets.
Not flagged
npm install -g @anthropic-ai/claude-codeand other lines that only mention an agent.- An agent name inside a quoted string, such as
echo "claude --dangerously-skip-permissions". - Other tools with the same name that receive no prompt, for example the AWS Copilot CLI (
copilot svc deploy). - Narrower modes:
--permission-mode acceptEdits,--sandbox workspace-write,--approval-mode auto_edit, and--allowedToolswithBash(<command pattern>). - Agents configured through settings files instead of flags. glsec only sees the command line.
See also
- GL002: user-controlled variables in scripts
- GL044: merge request jobs that check out the source branch
- GL080: sensitive jobs without a source guard
Documentation for glsec 1.23.0. Source of this page · Rule implementation