Back to skill

Security audit

Jules API

Security checks for vulnerabilities and agentic risk

Overview

This skill is for a real Jules API workflow, but it can start autonomous repository work with permissive defaults and delete remote sessions without confirmation.

Install only if you intend to give this skill access to a Jules API key connected to repositories you are comfortable operating on. Prefer requiring plan approval, avoid auto-PR mode unless explicitly needed, review prompts and target branches before sending them, and be careful with the delete command because the helper does not ask for confirmation.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/jules.sh:77
Finding
Unsafe JSON Construction Permits Request-Body Manipulation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/jules.sh`, lines 77-103 **Vulnerability Type**: Improper escaping of user-controlled JSON values **Risk Level**: Medium ### Vulnerable Code ```bash SOURCE_ID="$2" BRANCH="$3" PROMPT="$4" TITLE="${5:-}" REQUIRE_APPROVAL="false" AUTOMATION_MODE="" shift 4 for arg in "$@"; do case "$arg" in --approve) REQUIRE_APPROVAL="true" ;; --auto-pr) AUTOMATION_MODE="AUTO_CREATE_PR" ;; *) TITLE="$arg" ;; esac done # Build JSON body BODY="{\"prompt\":$(echo "$PROMPT" | jq -Rs .),\"sourceContext\":{\"source\":\"sources/$SOURCE_ID\",\"githubRepoContext\":{\"startingBranch\":\"$BRANCH\"}},\"requirePlanApproval\":$REQUIRE_APPROVAL" if [ -n "$TITLE" ] && [ "$TITLE" != "--approve" ] && [ "$TITLE" != "--auto-pr" ]; then BODY="$BODY,\"title\":$(echo "$TITLE" | jq -Rs .)" fi if [ -n "$AUTOMATION_MODE" ]; then BODY="$BODY,\"automationMode\":\"$AUTOMATION_MODE\"" fi BODY="$BODY}" post "$BASE_URL/sessions" "$BODY" | pretty ``` ### Technical Analysis The script incorporates the user-controlled `SOURCE_ID` and `BRANCH` arguments directly into a JSON string without JSON encoding them. In contrast, `PROMPT` and `TITLE` are encoded using `jq -Rs .`. An argument containing quotation marks or JSON structural characters can terminate the intended string and inject additional JSON properties. Depending on how the Jules API handles duplicate fields, an attacker may be able to alter the source context, branch, approval requirement, automation mode, or other supported session properties. Even if the API rejects duplicate or unknown properties, malformed input can reliably invalidate the request and cause denial of service. This is JSON injection rather than shell command injection: shell quoting prevents the arguments from becoming shell syntax, but it does not make them safe for insertion into JSON. ### Attack Path 1. An attacker gains influence over arguments passed to the `create` command, such as through ...[truncated 895 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Construct the entire request with `jq` rather than concatenating JSON strings. Pass every string value through `--arg`, and pass booleans through `--argjson`. For example: ```bash BODY=$(jq -n \ --arg prompt "$PROMPT" \ --arg source "sources/$SOURCE_ID" \ --arg branch "$BRANCH" \ --arg title "$TITLE" \ --arg automationMode "$AUTOMATION_MODE" \ --argjson requirePlanApproval "$REQUIRE_APPROVAL" \ '{ prompt: $prompt, sourceContext: { source: $source, githubRepoContext: {startingBranch: $branch} }, requirePlanApproval: $requirePlanApproval } + if $title != "" then {title: $title} else {} end + if $automationMode != "" then {automationMode: $automationMode} else {} end') ``` Additionally: - Validate `SOURCE_ID` against the exact resource-name format expected by the API. - Validate branch names using an allowlist or Git-compatible branch-name rules. - Reject control characters and unexpected resource path separators. - Treat API-side validation as defense in depth, not as a substitute for correct JSON encoding. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/jules.sh:28
Finding
Jules API Key Is Passed Through the Curl Process Argument Vector<![CDATA[ ## Vulnerability Details **File Location**: `scripts/jules.sh`, lines 28-43 **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Low ### Vulnerable Code ```bash AUTH_HEADER="x-goog-api-key: $JULES_API_KEY" # Helper: make GET request get() { curl -s -H "$AUTH_HEADER" "$1" } # Helper: make POST request with JSON body post() { curl -s -X POST -H "$AUTH_HEADER" -H "Content-Type: application/json" -d "$2" "$1" } # Helper: make DELETE request delete_req() { curl -s -X DELETE -H "$AUTH_HEADER" "$1" } ``` ### Technical Analysis The API key is embedded in the value passed to curl's `-H` command-line option. While shell quoting protects the value from shell expansion, it does not remove the credential from curl's process argument vector. On systems where process command lines are visible to other local users, monitoring agents, diagnostic tools, or container peers, the complete `x-goog-api-key` header may be observable while curl is running. The exposure window is normally short, but repeated API calls and polling increase opportunities for observation. ### Attack Path 1. The script invokes curl with `-H "x-goog-api-key: <secret>"`. 2. The API key becomes part of curl's process arguments. 3. A local actor with permission to inspect process metadata monitors process listings or the relevant process filesystem interface. 4. The actor captures the header value while curl is active. 5. The stolen key is replayed directly against the Jules REST API. ### Impact Assessment A stolen key grants the privileges assigned to the corresponding Jules account and API credential. Based on the implemented operations, this may include: - Enumerating connected repositories and branches. - Reading sessions, activities, generated patches, command output, and other artifacts. - Creating autonomous coding sessions. - Approving plans and sending instructions. - Deleting sessions. - Initiating automatic pull-request workflows ...[truncated 151 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid placing secret headers directly in command-line arguments where the deployment environment exposes process metadata. Depending on platform support, use a protected curl configuration supplied through standard input or a restricted temporary descriptor rather than an argument containing the key. Additional hardening measures include: - Ensure process command lines are not visible across user or container boundaries. - Run the Skill under a dedicated, least-privileged operating-system account. - Use a narrowly scoped API credential if the service supports scope restrictions. - Prevent debug tracing such as `set -x` around credential-handling code. - Redact headers from process telemetry and diagnostic logs. - Rotate the key immediately if process inspection or telemetry may already have captured it. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/jules.sh:83
Finding
Autonomous Repository Task Execution Is Enabled by Default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/jules.sh`, lines 83-96 **Vulnerability Type**: Insecure default for approval-sensitive autonomous actions **Risk Level**: Low ### Vulnerable Code ```bash REQUIRE_APPROVAL="false" AUTOMATION_MODE="" shift 4 for arg in "$@"; do case "$arg" in --approve) REQUIRE_APPROVAL="true" ;; --auto-pr) AUTOMATION_MODE="AUTO_CREATE_PR" ;; *) TITLE="$arg" ;; esac done # Build JSON body BODY="{\"prompt\":$(echo "$PROMPT" | jq -Rs .),\"sourceContext\":{\"source\":\"sources/$SOURCE_ID\",\"githubRepoContext\":{\"startingBranch\":\"$BRANCH\"}},\"requirePlanApproval\":$REQUIRE_APPROVAL" ``` ### Technical Analysis The session creation command initializes `REQUIRE_APPROVAL` to `false`. Consequently, a coding task proceeds without explicit plan approval unless the caller adds `--approve`. This reverses the safer default for an agent authorized to modify connected source repositories. A malformed, misunderstood, or attacker-influenced prompt may begin execution before a human has reviewed the proposed plan. The risk is greater in automated environments where command arguments are assembled from issue descriptions, chat input, or other untrusted content. The behavior is documented by the command help, so it is not hidden functionality. The security concern is the permissive default rather than a discrepancy between documentation and implementation. ### Attack Path 1. A user or automated workflow invokes `jules.sh create` without `--approve`. 2. The script sets `requirePlanApproval` to `false`. 3. A flawed or attacker-influenced prompt is submitted under the user's Jules API credentials. 4. Jules begins the repository task without presenting a mandatory approval checkpoint. 5. The agent may generate and apply unintended changes; if `--auto-pr` is also supplied, it may automatically open a pull request. ### Impact Assessment The operation remains constrained by the repositories and capabilities availa ...[truncated 389 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Adopt plan approval as the default: ```bash REQUIRE_APPROVAL="true" for arg in "$@"; do case "$arg" in --no-approve) REQUIRE_APPROVAL="false" ;; --auto-pr) AUTOMATION_MODE="AUTO_CREATE_PR" ;; *) TITLE="$arg" ;; esac done ``` Further hardening should include: - Require an explicit, clearly named override such as `--no-approve`. - Display a warning and request confirmation when approval is disabled. - Require separate confirmation before enabling `AUTO_CREATE_PR`. - Prevent unattended workflows from disabling approval unless explicitly authorized by policy. - Log the selected repository, branch, approval setting, and automation mode before submission without logging the API key. - Validate and display the final task configuration for review before sending the request. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Exfiltration Commands

High
Category
Prompt Injection
Content
#   sessions [pageSize]                        - List sessions
#   session <sessionId>                        - Get session details
#   approve <sessionId>                        - Approve a pending plan
#   message <sessionId> <message>              - Send message to session
#   activities <sessionId> [pageSize]          - List session activities
#   activity <sessionId> <activityId>          - Get single activity
#   delete <sessionId>                         - Delete a session
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Exfiltration Commands

High
Category
Prompt Injection
Content
#   sessions [pageSize]                        - List sessions
#   session <sessionId>                        - Get session details
#   approve <sessionId>                        - Approve a pending plan
#   message <sessionId> <message>              - Send message to session
#   activities <sessionId> [pageSize]          - List session activities
#   activity <sessionId> <activityId>          - Get single activity
#   delete <sessionId>                         - Delete a session
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell commands with curl and makes network requests, but it declares no tool scope such as allowed-tools or permissions. That omission weakens user and platform visibility into what the skill can do and increases the chance of unintended shell/network execution without explicit consent boundaries.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Jules API Skill

Interact with the [Google Jules](https://jules.google) AI coding agent via its REST API. Jules can autonomously execute coding tasks on your GitHub repositories — writing code, fixing bugs, adding tests, and creating pull requests.

**Base URL:** `https://jules.googleapis.com/v1alpha`
**Auth:** Pass your API key via the `x-goog-api-key` header. Get one at [jules.google.com/settings](https://jules.google.com/settings).
Confidence
93% confidence
Finding
The skill explicitly enables an external AI agent to autonomously execute coding tasks on GitHub repositories, including writing code and creating pull requests. In this context, autonomy materially increases risk because actions can affect real repositories and codebases, potentially causing unauthorized or poorly reviewed changes if invoked carelessly.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill advertises autonomous coding actions on GitHub repositories, including writing code and creating pull requests, without a prominent warning that it can modify external repositories. Users may invoke it without appreciating that it can trigger real changes to source code and repository state outside the local environment.

External Transmission

Medium
Category
Data Exfiltration
Content
Discover which GitHub repos are connected to your Jules account:

```bash
curl -s -H "x-goog-api-key: $JULES_API_KEY" \
  "https://jules.googleapis.com/v1alpha/sources?pageSize=30"
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| `requirePlanApproval` | No | If `true`, plans need explicit approval before execution |
| `automationMode` | No | Set to `AUTO_CREATE_PR` to auto-create PRs when done |

### Auto-approve + Auto-PR example

```bash
curl -s -X POST \
Confidence
90% confidence
Finding
The auto-approve/auto-PR workflow compounds autonomous behavior by reducing or removing human checkpoints before external repository changes are made. In a coding-agent skill tied to GitHub repositories, this creates a heightened risk of unintended commits, unsafe code generation, or PR spam against connected projects.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The auto-create PR example encourages fully automated external repository modification without an adjacent warning about the consequences. This is dangerous because it normalizes unattended code changes and PR creation against connected repositories, which can lead to accidental or inappropriate modifications.

External Transmission

Medium
Category
Data Exfiltration
Content
### Auto-approve + Auto-PR example

```bash
curl -s -X POST \
  -H "x-goog-api-key: $JULES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
84% confidence
Finding
This POST request sends task prompts and repository context to an external AI coding service that can act on connected repositories and create PRs. In context, the danger is not mere transmission but transmission coupled with automated remote code modification, especially in an example that omits strong warnings or safer gating defaults.

External Transmission

Medium
Category
Data Exfiltration
Content
When a session is in `AWAITING_PLAN_APPROVAL` state, approve the plan:

```bash
curl -s -X POST \
  -H "x-goog-api-key: $JULES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}' \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The delete-session command documents a destructive API action without warning that deletion may be irreversible and may remove history or artifacts needed for auditability. Even if limited to sessions rather than repository code, destructive operations should be clearly labeled to reduce accidental loss.

External Transmission

Medium
Category
Data Exfiltration
Content
# Helper: make GET request
get() {
  curl -s -H "$AUTH_HEADER" "$1"
}

# Helper: make POST request with JSON body
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
echo "Usage: jules.sh create <sourceId> <branch> <prompt> [title] [--approve] [--auto-pr]" >&2
      echo "  sourceId: e.g. github-owner-repo" >&2
      echo "  branch:   e.g. main" >&2
      echo "  --approve: require plan approval (default: auto-approve)" >&2
      echo "  --auto-pr: auto-create PR when done" >&2
      exit 1
    fi
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The `delete` command issues an HTTP DELETE request for a session immediately after checking that a session ID was provided. There is no confirmation prompt, cautionary message, or other user-facing disclosure near this destructive operation, despite it being irreversible from the user's perspective.

Static analysis

No suspicious patterns detected.