Back to skill

Security audit

Openclaw Fullstack App

Security checks for vulnerabilities and agentic risk

Overview

This generator is mostly aligned with its stated purpose, but it can overwrite existing files and can generate Docker configuration that runs an arbitrary database image with weak default security settings.

Review this skill before use. Run the generator only in a new empty directory, do not pass untrusted arguments, replace the database image with a trusted pinned image, and change the generated credentials and CORS policy before deploying or committing the project.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
generate.sh:15
Finding
Unrestricted Target Directory Allows Overwriting Existing Project Files<![CDATA[ ## Vulnerability Details **File Location**: `generate.sh:10,15-16` **Vulnerability Type**: Unvalidated filesystem destination and unsafe file overwrite **Risk Level**: Medium ### Vulnerable Code ```bash NAME="${1:-my-app}" FRONTEND="${2:-react}" BACKEND="${3:-node}" DB="${4:-postgresql}" echo "🚀 Generating fullstack app: $NAME" echo "📦 Frontend: $FRONTEND | Backend: $BACKEND | DB: $DB" # Create directory mkdir -p "$NAME" cd "$NAME" ``` The script subsequently uses truncating output redirections to write predictable files under the selected destination, including: ```bash cat > frontend/package.json << EOF ``` ```bash cat > backend/package.json << EOF ``` ```bash cat > docker-compose.yml << EOF ``` ### Technical Analysis The first argument is accepted as a filesystem path without checking whether it is: - An absolute path. - A path containing traversal components such as `../`. - An existing or non-empty directory. - Located outside an approved generation directory. Although quoting prevents shell word splitting, it does not constrain where the script writes. `mkdir -p` accepts existing directories, after which `cd "$NAME"` makes the attacker-selected directory the base for all generated files. The `cat > file` operations truncate existing files without confirmation. The vulnerability is therefore an arbitrary destination write within the permissions of the user running the generator. It is not arbitrary-content file writing, because the generated contents are largely fixed, but it can destructively replace predictable project files. ### Attack Path 1. An attacker influences the first argument supplied to `generate.sh`. 2. The attacker selects an existing writable directory, such as an unrelated application directory, using an absolute or traversal path. 3. `mkdir -p` succeeds because the directory already exists. 4. The script changes into that directory. 5. Existing files such as `frontend/package.json`, `backend/package.json`, `bac ...[truncated 715 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require the application name to be a safe basename rather than an arbitrary path: ```bash NAME="${1:-my-app}" if [[ ! "$NAME" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then echo "Invalid application name" >&2 exit 1 fi ``` 2. Generate applications beneath a fixed, explicitly selected base directory and verify the resulting path remains inside it. 3. Reject absolute paths, `.` and `..` path components, path separators, and empty names. 4. Refuse to use an existing non-empty destination unless an explicit, clearly documented overwrite option is supplied. 5. Before each redirection, verify that the destination does not already exist and is not a symbolic link. 6. Run the generator with the least-privileged account required for the task. ]]>

T08 · Insecure Dependencies

Error
Location
generate.sh:172
Finding
Unvalidated Database Image Permits Attacker-Controlled Container Execution<![CDATA[ ## Vulnerability Details **File Location**: `generate.sh:13,156-175` **Vulnerability Type**: Untrusted container image selection **Risk Level**: High ### Vulnerable Code The fourth command-line argument is accepted without validation: ```bash DB="${4:-postgresql}" ``` It is inserted directly into the generated Compose configuration: ```bash # Create docker-compose cat > docker-compose.yml << EOF version: '3.8' services: frontend: build: ./frontend ports: - "3000:3000" depends_on: - backend backend: build: ./backend ports: - "${BACKEND:-$((3000+1))}" environment: - DATABASE_URL=postgresql://user:pass@db:5432/$NAME db: image: $DB environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: $NAME EOF ``` ### Technical Analysis The `DB` value is used as the `db` service image reference without an allowlist, trusted registry restriction, version constraint, or immutable digest. A caller can therefore choose an arbitrary public or private registry image. The generated script instructs the user to run `docker-compose up`. When that command is executed, Docker resolves, downloads, and starts the selected image. As a result, data that appears to select a database implementation becomes a deferred container-code execution channel. The malicious code executes inside the container rather than automatically obtaining host-level privileges. However, it receives the container's configured environment, access to the Compose network, and the ability to interact with other reachable services. Its effective privileges may increase if the generated Compose file is later extended with host mounts, elevated capabilities, host networking, or Docker socket access. ### Attack Path 1. An attacker persuades a user or automation process to invoke the generator with an attacker-controlled fourth argument, for example: ```bash ./generate.sh example react node attacker.example/ma ...[truncated 1193 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace arbitrary image selection with a strict mapping of supported database choices: ```bash case "$DB" in postgresql) DB_IMAGE="postgres:16.4" ;; mongodb) DB_IMAGE="mongo:7.0.14" ;; *) echo "Unsupported database: $DB" >&2 exit 1 ;; esac ``` 2. Use `$DB_IMAGE` in the generated Compose file rather than the original argument. 3. Prefer immutable image digests for release or production templates: ```yaml image: postgres:16.4@sha256:<trusted-digest> ``` 4. Restrict images to trusted publishers and registries. 5. Verify image signatures or provenance where the deployment platform supports it. 6. Document every accepted command-line argument so users understand that selecting a database affects executable container content. 7. Run generated containers as non-root users, apply read-only filesystems where practical, drop unnecessary Linux capabilities, and avoid Docker socket or sensitive host mounts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
generate.sh:165
Finding
Generated Deployment Uses Predictable Hard-Coded Database Credentials<![CDATA[ ## Vulnerability Details **File Location**: `generate.sh:165-175` **Vulnerability Type**: Hard-coded plaintext credentials **Risk Level**: Medium ### Vulnerable Code ```bash backend: build: ./backend ports: - "${BACKEND:-$((3000+1))}" environment: - DATABASE_URL=postgresql://user:pass@db:5432/$NAME db: image: $DB environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: $NAME ``` ### Technical Analysis Every generated project uses the same predictable database username and password: ```text user:pass ``` The credentials are stored in plaintext in `docker-compose.yml` and duplicated inside `DATABASE_URL`. Generated projects are likely to be placed under source control, causing these values to become part of repository history. In the supplied template, the database service is not directly published to a host port. This reduces immediate external exposure, but the credentials remain usable by any process with access to the Compose network. They also become dangerous if a user later publishes the database port or deploys the same configuration to a shared environment. ### Attack Path 1. A project is generated with the default Compose configuration. 2. The generated `docker-compose.yml` is committed, shared, archived, or deployed without replacing the defaults. 3. An attacker reads the predictable credentials from the repository or simply knows the generator's defaults. 4. The attacker obtains network access to the database through a compromised adjacent container, a later-added published port, or a shared deployment network. 5. The attacker authenticates using `user:pass`. 6. The attacker receives the permissions assigned to the generated PostgreSQL user over the generated application database. ### Impact Assessment The obtainable privileges are those granted to the configured database account. Within the generated environment, this may allow reading, modifying, or deleting ap ...[truncated 380 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove literal credentials from the generated Compose file. 2. Use environment-variable interpolation and provide only a non-secret `.env.example`: ```yaml environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} ``` 3. Construct `DATABASE_URL` from protected environment values rather than embedding a password in committed configuration. 4. Generate a strong random password for local development at generation time and place it in a permissions-restricted `.env` file. 5. Add `.env` and other secret-bearing files to `.gitignore`. 6. For deployed environments, use Docker secrets, an orchestration-platform secret store, or a dedicated secrets manager. 7. Assign the database account only the permissions required by the application and use separate credentials for development, testing, staging, and production. 8. Add startup validation that rejects known placeholder passwords such as `pass`. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
generate.sh:124
Finding
Python Backend Template Generates an Overly Permissive Credentialed CORS Policy<![CDATA[ ## Vulnerability Details **File Location**: `generate.sh:124-137` **Vulnerability Type**: Permissive cross-origin resource sharing configuration **Risk Level**: Low ### Vulnerable Code ```bash cat > backend/app/main.py << EOF from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) ``` ### Technical Analysis The generated FastAPI backend allows all origins, HTTP methods, and request headers while also enabling credential support. This configuration does not establish a trusted-origin boundary and is unsafe boilerplate for an application expected to add authentication. CORS behavior for wildcard origins combined with credentials depends on browser rules and middleware implementation. In credentialed scenarios, middleware may reflect an incoming origin rather than returning a literal wildcard. Consequently, this configuration should not be treated as protection against requests from untrusted websites. The currently generated Python application exposes only an unauthenticated health endpoint, so no sensitive data is immediately exposed by the template itself. The risk materializes when users add authenticated or sensitive endpoints without first replacing the generated CORS policy. ### Attack Path 1. A user generates the Python backend and retains the default CORS configuration. 2. The user adds authenticated or sensitive API endpoints. 3. Authentication is implemented using cookies or another browser-accessible credential mechanism. 4. A victim visits an attacker-controlled website while authenticated to the generated application. 5. The attacker's page sends cross-origin requests to the API. 6. If the middleware and browser permit the origin under the generated policy, the request executes with the victim's credentials and may expose readable responses to t ...[truncated 517 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace wildcard origins with an explicit list of trusted frontend origins: ```python app.add_middleware( CORSMiddleware, allow_origins=["https://app.example.com"], allow_credentials=True, allow_methods=["GET", "POST"], allow_headers=["Authorization", "Content-Type"], ) ``` 2. Disable `allow_credentials` unless browser credentials are explicitly required. 3. Configure separate origin lists for local development and deployed environments. 4. Validate configured origins at startup and reject wildcard origins when credential support is enabled. 5. Allow only the HTTP methods and headers required by the API. 6. Treat CORS as a browser access-control mechanism rather than an authentication or authorization control; continue enforcing authorization on every sensitive endpoint. 7. Add automated tests confirming that requests from untrusted origins do not receive permissive CORS response headers. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Low
Confidence
86% confidence
Finding
This shell script creates directories and writes several files including package manifests, source files, and docker-compose configuration. While it prints high-level generation status, it does not explicitly disclose that it will overwrite/create files across many paths or warn the user about the scope of those writes.

Static analysis

No suspicious patterns detected.