Back to skill

Security audit

form-builder

Security checks for vulnerabilities and agentic risk

Overview

The skill is a form builder, but it publishes PostgreSQL credentials and describes writing new records to a RoadFlow database without clear safeguards.

Review carefully before installing. Do not use this package with the published database credentials; treat that password as compromised and rotate it. Use only dedicated least-privilege credentials from a secret manager or environment variables, and require a dry-run plus explicit confirmation before any rf_form database writes.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:78
Finding
Plaintext PostgreSQL Administrator Credentials Exposed in Skill Documentation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 78-83 **Vulnerability Type**: Hard-coded plaintext credentials **Risk Level**: High ### Vulnerable Code ```markdown ## Database Configuration (roadflow) - **Host**: 192.168.1.136 - **Port**: 35438 - **User**: postgres - **Password**: Hxkj510510 - **Target Database**: roadflow ``` ### Technical Analysis The Skill documentation contains a complete PostgreSQL connection profile, including a plaintext password and the privileged-looking `postgres` username. Anyone who can read the Skill package can recover the credential without needing to inspect runtime configuration or defeat any access controls. Secrets committed to documentation are also likely to persist in package archives, backups, caches, and source-control history after the visible value is removed. Although the database uses a private IP address, that does not make the credential safe: users, agents, compromised hosts, or services with access to the relevant internal network could attempt to use it. The audit could not verify whether the credential remains active or determine its exact database privileges. Nevertheless, publishing a password in the package is independently an insecure credential-management practice. ### Attack Path 1. An attacker obtains read access to the Skill package or a copy of its documentation. 2. The attacker reads `SKILL.md` and extracts the host, port, username, password, and database name. 3. From a host that can reach `192.168.1.136:35438`, the attacker attempts to authenticate to PostgreSQL with the disclosed credentials. 4. If the credential is active, the attacker performs operations permitted to the `postgres` account. 5. If the password has been reused, the attacker may attempt to authenticate to other related database instances or services. ### Impact Assessment If the credential is valid and the database is reachable, the attacker could obtain all privileges assigned to the disclosed acc ...[truncated 512 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed password immediately; do not merely remove it from the current document. 2. Review PostgreSQL authentication logs for use of the exposed account from unexpected hosts. 3. Search source-control history, package registries, build artifacts, backups, and caches for additional copies of the credential. 4. Replace the `postgres` account with a dedicated RoadFlow service account that has only the table and operation permissions required by the Skill. 5. Store the replacement credential in an approved secret manager. If that is unavailable, obtain it through protected runtime environment variables rather than committing it to files. 6. Document only placeholder configuration, such as `ROADFLOW_DB_HOST` and `ROADFLOW_DB_PASSWORD`. 7. Restrict database ingress to explicitly authorized hosts and require encrypted PostgreSQL connections. 8. Establish automated secret scanning in commit and release pipelines to prevent recurrence. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/html_form_generator.js:55
Finding
HTML Injection and Cross-Site Scripting in Generated Forms<![CDATA[ ## Vulnerability Details **File Location**: `scripts/html_form_generator.js`, lines 55-111 **Vulnerability Type**: Unescaped HTML generation **Risk Level**: Medium ### Vulnerable Code The generator inserts option values into both HTML attribute and text contexts without escaping: ```javascript let optionsHtml = field.options.map(opt => `<option value="${opt}">${opt}</option>`).join(''); ``` Radio-option values and labels are handled in the same way: ```javascript fieldHtml = field.options.map((opt, idx) => `<div class="form-check"> <input class="form-check-input" type="radio" name="${field.fieldName}" value="${opt}" id="rf_${field.fieldName}_${idx}"> <label class="form-check-label" for="rf_${field.fieldName}_${idx}">${opt}</label> </div>` ).join(''); ``` Input properties are also interpolated directly into attribute contexts: ```javascript fieldHtml = `<input type="${field.fieldType}" class="form-control ${field.required ? '' : 'is-invalid'}`} name="${field.fieldName}" placeholder="${field.placeholder || ''}" value="${field.value || ''}" required="${field.required || ''}"${field.minMaxStep.min ? ` min="${field.minMaxStep.min}"` : ''}${field.minMaxStep.max ? ` max="${field.minMaxStep.max}"` : ''}${field.minMaxStep.step ? ` step="${field.minMaxStep.step}"` : ''}${field.minLength ? ` minlength="${field.minLength}"` : ''}${field.maxLength ? ` maxlength="${field.maxLength}"` : ''}"${field.autocomplete ? ` autocomplete="${field.autocomplete}"` : ''}">`; ``` The form title, container class, and field labels are inserted into the final document without contextual encoding: ```javascript let html = `<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>${formTitle || '表单'}</title>\n <!-- Bootstrap 5 CSS -->\n <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">\n <style>\n .need ...[truncated 3437 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply context-specific encoding to every dynamic value: - HTML text encoding for titles, labels, and option display text - HTML attribute encoding for names, values, placeholders, IDs, classes, and autocomplete values 2. Do not use one generic replacement function for all contexts. Encode quotation marks, ampersands, angle brackets, and apostrophes appropriately for attribute contexts. 3. Prefer constructing forms with DOM APIs such as `document.createElement`, `textContent`, and `setAttribute`, or use a maintained template engine with automatic escaping enabled. 4. Allowlist supported input types rather than inserting arbitrary `fieldType` values. 5. Restrict field names and generated IDs to a conservative pattern such as letters, digits, underscores, and hyphens. 6. Validate configurable CSS classes against a fixed set instead of accepting arbitrary class strings. 7. Treat titles, defaults, placeholders, and enumeration entries as untrusted even when they originate from a JSON Schema. 8. Add tests containing malicious values in every supported field, including quotation marks, closing tags, event-handler attributes, and script elements. 9. Deploy generated forms with a restrictive Content Security Policy as defense in depth. CSP must not replace correct output encoding. 10. If generated forms are previewed, render them in a sandboxed iframe on a separate origin without access to application credentials. ]]>
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill embeds live PostgreSQL connection details, including host, port, username, and password, directly in documentation. Hardcoded credentials expose unauthorized access to the roadflow database and can enable data theft, tampering, or destructive writes, especially because the skill explicitly supports reading and saving forms to persistent storage.

Missing User Warnings

High
Confidence
99% confidence
Finding
Publishing database credentials and internal connection details without any security boundary or warning materially increases the likelihood of compromise. Because the same section identifies the specific target database and the skill’s ability to modify rf_form records, an attacker or misused agent has everything needed to connect and alter sensitive application data.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill describes a workflow that queries existing database records, copies form definitions, modifies them, and saves new records without any approval, confirmation, or warning about persistent side effects. In an agent setting, this can lead to unauthorized or accidental writes to production data, cloning of sensitive form contents, and integrity issues in the rf_form table.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The markdown states that filled form data may be stored in sessionStorage/localStorage, which can retain user-entered information on the client device. There is no warning about privacy implications, sensitive data handling, or advising when not to use browser storage.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The help text states `--framework Bootstrap|Tailwind`, implying users can choose between two output frameworks. However, all generation paths call `generateBootstrapForm` and there is no Tailwind-specific renderer or framework selection logic anywhere in the file, so the documentation materially overstates the implemented behavior.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file’s descriptive text and generated validation messages are written in Chinese, and the phone validation is also tailored to a China-specific locale. Because the skill does not offer any user opt-in or language/locale selection, it enforces a specific language/locale by default, which matches the natural-language policy violation criteria.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The manifest includes author-identifying text entirely in Chinese characters, which is a natural-language locale signal in a user-facing metadata field. Because there is no indication elsewhere in the file that language choice is optional or user-selectable, this can conflict with the policy against forcing a specific language or locale without opt-in.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The generated document always uses `<html lang="en">` even though the tool’s surrounding help text and comments are in Chinese and there is no option for users to choose or override the locale. This is a natural-language locale policy issue because it forces a specific language setting without opt-in or documented justification.

Static analysis

No suspicious patterns detected.