Back to skill

Security audit

ReAct Loop

Security checks for vulnerabilities and agentic risk

Overview

This markdown-only ReAct skill is not malicious, but it needs review because its examples normalize migrations, deployments, outbound messages, and unsafe payment code without explicit approval limits.

Review this skill before installing. It is documentation-only and does not contain an installer or hidden code, but users should require explicit approval before any agent follows its examples to deploy, run migrations, query sensitive data, or send external communications. Do not copy the Stripe payment example into production without redesigning server-side amount validation and error handling.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
references/examples.md:95
Finding
Client-Controlled Payment Amount and Excessive Stripe Error Disclosure## Vulnerability Details **File Location**: `references/examples.md`, lines 95–108 **Vulnerability Type**: Client-controlled transaction integrity and excessive error disclosure **Risk Level**: High ### Vulnerable Code ```python @app.route('/api/create-payment-intent', methods=['POST']) def create_payment(): try: data = request.get_json() intent = stripe.PaymentIntent.create( amount=data['amount'], currency='usd', automatic_payment_methods={'enabled': True}, idempotency_key=data.get('idempotency_key') ) return jsonify(client_secret=intent.client_secret) except stripe.error.StripeError as e: return jsonify(error=str(e)), 400 ``` ### Technical Analysis The example creates a Stripe PaymentIntent using `data['amount']`, which is supplied directly by the requesting client. It does not show an authenticated order lookup, server-side price calculation, ownership or authorization validation, accepted-currency validation, amount bounds checking, or binding of the PaymentIntent to an authoritative order record. Client input cannot be trusted to define the amount owed. A user can modify the HTTP request independently of any browser-side validation and request a PaymentIntent for an arbitrarily reduced amount. If fulfillment relies only on the PaymentIntent succeeding and does not independently compare its amount and currency with the authoritative order total, the user may obtain higher-value goods or services after making an insufficient payment. The handler also returns `str(e)` directly to the requester. Stripe exception strings can contain provider diagnostics and integration details that should generally remain in sanitized server-side logs. Although the affected content is reference documentation rather than an automatically executed application, the example is presented as implementation guidance and could propagate th ...[truncated 1558 chars]
Remediation
## Remediation Suggestions 1. Do not accept the payable amount as authoritative client input. Accept only an authenticated cart or order identifier. 2. Load the order from trusted server-side storage and verify that it belongs to the authenticated user and remains payable. 3. Recalculate the total server-side using authoritative product prices, quantities, discounts, taxes, shipping charges, and currency rules. 4. Validate that the amount is an integer in the currency's smallest unit and falls within permitted bounds. 5. Generate the idempotency key server-side or bind it to the authenticated order and operation. Do not rely on an arbitrary client-provided key. 6. Store the PaymentIntent ID against the order and include a non-sensitive internal order identifier in Stripe metadata. 7. Before fulfillment, verify the webhook signature and confirm the PaymentIntent ID, status, amount received, currency, order association, and fulfillment state against authoritative records. 8. Make fulfillment idempotent and perform the validation and state transition atomically to prevent duplicate or mismatched fulfillment. 9. Return a generic error message and stable application error code to the client. Log sanitized Stripe diagnostics server-side without exposing secrets or sensitive payment information. 10. Add negative tests that modify the request amount, currency, order identifier, ownership, and idempotency key, and verify that underpaid or mismatched transactions cannot be fulfilled. A safer design is: ```python @app.route('/api/create-payment-intent', methods=['POST']) @login_required def create_payment(): data = request.get_json(silent=True) or {} order = Order.get_payable_for_user( order_id=data.get('order_id'), user_id=current_user.id ) if order is None: return jsonify(error='Invalid order'), 400 amount = order.calculate_total_minor_units() try: intent = stripe. ...[truncated 588 chars]
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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Exfiltration Commands

High
Category
Prompt Injection
Content
```
ACTION: Send email to team with findings
ACTION: Post message to Slack channel
ACTION: Create GitHub issue
```
Confidence
90% confidence
Finding
The skill explicitly lists outbound communication actions such as sending email, posting to Slack, and creating GitHub issues. In the context of an agent skill, these are exfiltration-capable channels and can leak sensitive findings, code, logs, or internal state if invoked automatically or on untrusted prompts.

External Transmission

Medium
Category
Data Exfiltration
Content
ACTION: Search web for "Python async best practices 2024"
ACTION: Query database: SELECT * FROM users WHERE last_login > NOW() - INTERVAL '7 days'
ACTION: Read file: src/auth/middleware.py
ACTION: Fetch API: GET https://api.github.com/repos/owner/repo/issues
```

### Execution
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The skill is framed as a generic reasoning pattern, but its documented example actions explicitly include operational steps such as executing migrations, deploying to staging, sending email, posting to Slack, and creating GitHub issues. In a reusable agent skill, this broadens the skill from analysis into real-world side effects without any gating, which can normalize unsafe autonomous actions and increase the chance an agent performs impactful operations without explicit user confirmation.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The examples include sensitive or potentially destructive actions such as executing SQL migrations, deploying to staging, and sending outbound communications, but they are presented as ordinary loop steps with no warning, approval checkpoint, or safety caveat. This can encourage unsafe execution behavior by downstream agents or users who treat the examples as endorsed defaults.

Static analysis

No suspicious patterns detected.