Back to skill

Security audit

Dhh Rails Style

Security checks for vulnerabilities and agentic risk

Overview

This Rails style skill is mostly documentation, but it needs Review because it includes an incomplete SSRF protection pattern that could lead generated apps to unsafe code.

Install only if you want broad DHH/37signals Rails style guidance, and review generated security-sensitive code yourself. Do not copy the SSRF protection snippet as-is; use a complete outbound request policy with proper IP classification, scheme and port allowlists, redirect validation, timeouts, response limits, and tests. Also add your own privacy limits before collecting IP address, referrer, user agent, or similar request metadata.

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/architecture.md:575
Finding
Incomplete SSRF Address Validation in Recommended Security Pattern<![CDATA[ ## Vulnerability Details **File Location**: `references/architecture.md`, lines 575–589 **Vulnerability Type**: Server-Side Request Forgery (SSRF) due to incomplete IP-address validation **Risk Level**: High ### Vulnerable Code ```ruby def fetch_safely(url) uri = URI.parse(url) ip = Resolv.getaddress(uri.host) # Block private networks raise "Private IP" if private_ip?(ip) # Use pinned IP for request Net::HTTP.start(uri.host, uri.port, ipaddr: ip) { |http| ... } end def private_ip?(ip) ip.start_with?("127.", "10.", "192.168.") || ip.match?(/^172\.(1[6-9]|2[0-9]|3[0-1])\./) end ``` ### Technical Analysis The Skill presents this code as an SSRF protection pattern, but its address validation is an incomplete textual blocklist. It rejects only IPv4 loopback beginning with `127.`, the `10.0.0.0/8` range, addresses beginning with `192.168.`, and `172.16.0.0/12`. It does not reject several non-public destinations, including: - IPv4 link-local addresses such as `169.254.0.0/16`, including common cloud metadata endpoints. - IPv6 loopback, unique-local, and link-local ranges. - IPv4-mapped IPv6 representations. - Unspecified, multicast, carrier-grade NAT, and other reserved ranges. - Redirect destinations that may resolve to prohibited addresses. The example also does not explicitly restrict schemes, ports, redirect behavior, response size, or network timeouts. DNS pinning reduces DNS-rebinding exposure for the initial resolution, but it does not compensate for the incomplete destination policy. Because this is documentation rather than executable project code, exploitation requires a downstream application to adopt this example and pass attacker-controlled URLs to it. ### Attack Path 1. A developer copies the recommended `fetch_safely` pattern into a Rails application. 2. The application exposes functionality that accepts an attacker-controlled URL, such as URL previews, imports, webhook verification, or remote image retrieval. 3. ...[truncated 1419 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace the textual blocklist with a strict outbound-request policy: 1. Parse resolved addresses using Ruby's `IPAddr` rather than string prefixes. 2. Permit only explicitly supported schemes, normally `http` and `https`. 3. Reject every address that is not approved global unicast, covering IPv4 and IPv6 loopback, private, link-local, unique-local, unspecified, multicast, reserved, carrier-grade NAT, and IPv4-mapped IPv6 forms. 4. Prefer an explicit hostname or destination allowlist where the business workflow permits one. 5. Restrict destination ports to the minimum required set. 6. Resolve the hostname once and connect to the validated address while preserving the original hostname for TLS certificate and Host-header validation. 7. Disable redirects by default. If redirects are necessary, apply the complete scheme, port, hostname, DNS, and IP validation process independently to every redirect target. 8. Configure connection, read, and total request timeouts. 9. Limit response sizes and avoid automatically processing untrusted response formats. 10. Route outbound requests through a controlled egress proxy or firewall that blocks metadata, loopback, link-local, private, and reserved destinations. 11. Add regression tests for IPv4 and IPv6 edge cases, including `169.254.169.254`, IPv6 loopback, unique-local addresses, link-local addresses, IPv4-mapped IPv6 addresses, alternate textual representations, and redirect chains. 12. Document that this protection is required only when the application intentionally retrieves remote resources; generated code should not make outbound requests unless necessary for the requested feature. ]]>
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Ae1

High
Category
analysis-evasion
Content
| 3, view, frontend, turbo, stimulus, css | [frontend.md](./references/frontend.md) |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| 3, view, frontend, turbo, stimulus, css | [frontend.md](./references/frontend.md) |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```ruby
# Instead of this:
POST /cards/:id/close
DELETE /cards/:id/close
POST /cards/:id/archive

# Do this:
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```ruby
# Instead of this:
POST /cards/:id/close
DELETE /cards/:id/close
POST /cards/:id/archive

# Do this:
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Do this:
POST /cards/:id/closure      # create closure
DELETE /cards/:id/closure    # destroy closure
POST /cards/:id/archival     # create archival
```
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Do this:
POST /cards/:id/closure      # create closure
DELETE /cards/:id/closure    # destroy closure
POST /cards/:id/archival     # create archival
```
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Vague Triggers

Medium
Confidence
92% confidence
Finding
The skill declares very broad activation triggers such as any Ruby/Rails code generation, refactoring, code review, or mentions of DHH/37signals-related terms. That can cause the skill to activate on many ordinary development requests outside a narrowly scoped style-guidance use case, increasing the chance that its instructions override more appropriate task-specific or security-focused guidance.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill recommends storing request ID, user agent, IP address, and referrer in a global Current context without any privacy guidance, data minimization, retention limits, or warnings about sensitive handling. In a code-generation skill, this can normalize pervasive collection of identifying metadata and lead downstream implementations to log, persist, or expose it in ways that create privacy and compliance risk.

Missing User Warnings

Low
Confidence
79% confidence
Finding
This markdown file includes a code example that writes arbitrary content to the user's clipboard via `navigator.clipboard.writeText`, but the surrounding documentation does not mention that the action copies data outside the page context. For markdown files, SQP-2 applies when behaviour affecting user data or privacy is described without warning, and clipboard access merits a brief disclosure.

Static analysis

No suspicious patterns detected.