Back to skill

Security audit

Install Stack Flagos

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent GPU-container installer, but it uses broad Docker shell commands and mutable external package sources without enough validation or user control.

Install only in a disposable or snapshotted container. Confirm the exact container name, avoid accepting container names from untrusted input, prefer direct verified sources, pin commits and hashes where possible, and review the ~/.bashrc change before allowing it.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/detect_network.py:28
Finding
Automatic Retrieval and Execution of Mutable Code Through an Unverified Third-Party Mirror<![CDATA[ ## Vulnerability Details **File Location**: `scripts/detect_network.py:28-51`; execution sinks in `SKILL.md:128-169`; mirror policy in `references/network-mirrors.md:11-18` **Vulnerability Type**: Remote payload retrieval and software supply-chain exposure **Risk Level**: High ### Vulnerable Code ```python def detect_network(): """Detect network environment and return mirror config.""" github_ok, github_ms = probe_url("https://github.com") pypi_ok, pypi_ms = probe_url("https://pypi.org/simple/") # Use mirrors if unreachable or slow (>3s) need_github_mirror = not github_ok or github_ms > 3000 need_pypi_mirror = not pypi_ok or pypi_ms > 3000 result = { "github": { "direct_reachable": github_ok, "latency_ms": round(github_ms, 1) if github_ms >= 0 else None, "use_mirror": need_github_mirror, "prefix": "https://ghfast.top/https://github.com" if need_github_mirror else "https://github.com", }, "pypi": { "direct_reachable": pypi_ok, "latency_ms": round(pypi_ms, 1) if pypi_ms >= 0 else None, "use_mirror": need_pypi_mirror, "index_flag": "-i https://pypi.tuna.tsinghua.edu.cn/simple" if need_pypi_mirror else "", }, } return result ``` The selected source is subsequently used by the following commands: ```bash docker exec <CONTAINER> bash -c " cd /tmp && git clone ${GITHUB_PREFIX}/FlagOpen/FlagGems cd FlagGems && pip install ${PIP_INDEX} -e . " ``` ```bash docker exec <CONTAINER> bash -c " cd /tmp && git clone ${GITHUB_PREFIX}/flagos-ai/FlagCX cd FlagCX && git submodule update --init --recursive make <MAKE_FLAG> -j\$(nproc) " ``` ```bash docker exec <CONTAINER> bash -c " cd /tmp && git clone ${GITHUB_PREFIX}/flagos-ai/vllm-plugin-FL cd vllm-plugin-FL pip install ${PIP_INDEX} -r requirements.txt pip install --no-build-isolation -e . " ``` ### Technical Analysis The Skill switches from GitHub ...[truncated 3243 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic fallback to an unverified third-party GitHub proxy. Only use origins that the operator has explicitly approved. 2. Require explicit user confirmation before changing the repository or package source. 3. Pin every repository to a reviewed full commit SHA rather than cloning the current default branch. 4. Pin and verify recursive submodule commits. Reject any submodule URL or commit that is absent from an approved manifest. 5. Prefer signed release tags or release artifacts and verify signatures against pinned trusted keys. 6. Maintain SHA-256 hashes for downloaded wheels, source archives, and dependency artifacts. Abort on any mismatch. 7. Use dependency lock files with exact versions and hashes. Avoid installing mutable, unconstrained `requirements.txt` dependencies. 8. Remove unnecessary `--trusted-host` configuration and require normal certificate and hostname validation. 9. Build untrusted source in a restricted environment without credentials, host mounts, Docker sockets, excessive Linux capabilities, or unnecessary outbound network access. 10. Separate downloading, verification, building, and deployment. Only verified artifacts should enter the operational GPU container. 11. Record the final source URL, commit SHA, submodule SHAs, package hashes, and signature verification results in the installation report. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:42
Finding
Host-Side Shell Command Injection Through Unquoted Container Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:42-57`; the same substitution pattern recurs throughout `SKILL.md:75-190` **Vulnerability Type**: Shell command injection **Risk Level**: High ### Vulnerable Code The Skill obtains a container name from the user or orchestration context and substitutes it into shell commands without quoting: ```markdown If invoked standalone, ask the user for container name and GPU vendor. If invoked from `/flagrelease` orchestrator, these are passed as context. ``` ```bash docker inspect --format='{{.State.Status}}' <CONTAINER> | grep -q running ``` ```bash docker cp <SKILL_DIR>/scripts/collect_env_info.py <CONTAINER>:/tmp/ docker exec <CONTAINER> python3 /tmp/collect_env_info.py ``` The pattern is repeated in installation and persistence commands, including: ```bash docker exec <CONTAINER> pip install ${PIP_INDEX} vllm==0.13.0 ``` ```bash docker exec <CONTAINER> bash -c " cd /tmp && git clone ${GITHUB_PREFIX}/FlagOpen/FlagGems cd FlagGems && pip install ${PIP_INDEX} -e . " ``` ```bash docker exec <CONTAINER> bash -c "echo 'export FLAGCX_PATH=/tmp/FlagCX' >> ~/.bashrc" ``` ### Technical Analysis `<CONTAINER>` represents input supplied by a user or another orchestrating Skill. The instructions do not require validation against Docker's permitted container-name or container-ID syntax, nor do they require the value to be passed as a safely quoted positional argument. If the Agent performs direct textual substitution, shell metacharacters in the supplied value are interpreted by the host shell before Docker validates the container identifier. Characters such as semicolons, command substitutions, redirections, or shell operators can terminate or alter the intended Docker command. This is especially significant because the Skill declares broad shell access: ```yaml allowed-tools: "Bash(*) Read Edit Write Glob Grep WebSearch WebFetch AskUserQuestion" ``` The vulnerable substitution therefore crosses the i ...[truncated 2387 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate container names before constructing any command. Accept only Docker-compatible names or full hexadecimal container IDs. For example, use an allowlist expression equivalent to: ```text ^[a-zA-Z0-9][a-zA-Z0-9_.-]*$ ``` 2. Reject whitespace, shell metacharacters, command substitutions, redirections, control characters, and values beginning with command-line option prefixes where relevant. 3. Do not construct commands through textual interpolation. Invoke processes with argument arrays, such as: ```python subprocess.run( ["docker", "inspect", "--format={{.State.Status}}", container], check=True, timeout=30, ) ``` 4. Where Bash is unavoidable, pass the validated value as a positional parameter and quote every expansion: ```bash container="$1" docker inspect --format='{{.State.Status}}' "$container" ``` 5. Apply the same validation and argument separation to `<SKILL_DIR>`, vendor values, mirror values, make flags, adaptor values, and other substituted fields. 6. Restrict the declared Bash permission to the minimum required commands rather than granting unrestricted `Bash(*)`. 7. Treat values received from an orchestrating Skill as untrusted unless they carry explicit validation guarantees. 8. Run the Agent under a dedicated, unprivileged account. Avoid privileged containers, Docker socket mounts, and unnecessary membership in the Docker group. 9. Add automated tests using invalid identifiers containing whitespace and shell metacharacters, and verify that all such inputs are rejected before any command runs. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents this skill as an installer/orchestrator for the multi-package software stack, with responsibilities such as mirror detection, dependency sequencing, wheel choice, and installation inside a GPU container. The supplied code chunk is instead a validation script: it imports modules, queries pip metadata, checks Triton/FlagTree path characteristics, inspects vLLM plugin entry points, builds a JSON status report, and returns a pass/fail code. This is related to the declared domain but materially narrower and different in primary purpose. There is no package installation, no network activity for mirror detection, no dependency management, and no wheel selection logic. Therefore the description does not accurately represent what this code chunk actually does.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
de the container:

```bash
docker cp <SKILL_DIR>/scripts/validate_packages.py <CONTAINER>:/tmp/
docker exec <CONTAINER> python3 /tmp/validate_packages.py
```

This produces a comprehensive JSON report of all 5 packages with import status,
versions, and gate check.

### Step 5: Set Runtime Environment

If FlagCX installed successfully, persist FLAGCX_PATH:

```bash
docker exec <CONTAINER> bash -c "echo 'export FLAGCX_PATH=/tmp/FlagCX' >> ~/.bashrc"
```

### Step 6: Produce Final Report

Combine all results into structured output:

```json
{
  "status": "PASS | PARTIAL | FAIL",
  "stage": "install-stack",
  "container": "<name>",
  "vendor": "<vendor>",
  "network": {"github_mirror": true, "pypi_mirror": true},
  "python_version": "3.11",
  "glibc_version": "2.34",
  "packages": {
    "vllm": {"status": "PASS", "version": "0.13.0"},
    "flagtree": {"status": "PASS", "version": "0.4.1+ascend3.2"},
    "flaggems": {"status": "PASS", "version": "..."},
    "flagcx": {"status": "PASS", "ver
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Lp1

High
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The script has shell execution capability via `subprocess.run(..., shell=True, ...)`, but that capability is not reflected in the declared permissions. Undeclared execution capability is risky because reviewers and policy systems may underestimate what the skill can do, especially in a containerized install workflow that already has elevated package-management context.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
]
    for cmd, vendor in checks:
        try:
            r = subprocess.run(cmd, shell=True, capture_output=True, timeout=5)
            if r.returncode == 0 and r.stdout.strip():
                return vendor
        except Exception:
Confidence
95% confidence
Finding
Using `subprocess.run(cmd, shell=True, ...)` is a classic tool-parameter abuse pattern because a shell interprets the string instead of executing a binary directly. In this installer context, the risk is amplified by running inside a GPU container where package installation and environment setup may occur with powerful privileges, so shell execution increases exposure to PATH manipulation and future injection bugs.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill performs destructive package operations inside a running container, including uninstalling packages and installing editable/source-based dependencies, without a prominent upfront warning. This can break an existing environment, alter dependency resolution unexpectedly, and cause users to run high-impact changes without informed consent.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill persists changes to the shell profile by appending to ~/.bashrc, but does not clearly warn the user that the modification survives the current session. Persistent environment changes can affect future shell behavior, create hard-to-debug state, and in shared or long-lived containers can influence later tasks unexpectedly.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The instruction 'Always use FlagOS PyPI for FlagTree regardless of network' imposes a fixed repository choice in natural language without presenting user choice or opt-in. This can violate the policy against forcing a specific language/locale or region-specific constraint unless it is clearly justified and documented as such.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_glibc_version():
    try:
        result = subprocess.run(
            ["ldd", "--version"], capture_output=True, text=True, timeout=5
        )
        output = result.stdout + result.stderr
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    for cmd, vendor in checks:
        try:
            r = subprocess.run(cmd, shell=True, capture_output=True, timeout=5)
            if r.returncode == 0 and r.stdout.strip():
                return vendor
        except Exception:
Confidence
93% confidence
Finding
This subprocess invocation uses `shell=True`, which causes the command string to be interpreted by a shell. Although the current command values are hardcoded, this pattern is dangerous because it expands the attack surface through shell parsing and PATH hijacking inside the container; if environment state or command strings change later, it can become command execution.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def probe_url(url, timeout=5):
    """Test if a URL is reachable within timeout. Returns (reachable, latency_ms)."""
    try:
        result = subprocess.run(
            ["curl", "-s", "-o", "/dev/null", "-w", "%{time_total}",
             "--connect-timeout", str(timeout), url],
            capture_output=True, text=True, timeout=timeout + 2
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
version = getattr(mod, "__version__", None)
        if version is None:
            # Try pip show
            r = subprocess.run(
                [sys.executable, "-m", "pip", "show", module_name],
                capture_output=True, text=True, timeout=10
            )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
result["triton_path"] = path
        result["is_flagtree"] = "flagtree" in path.lower() or "flag_tree" in path.lower()
        # Get version from pip
        r = subprocess.run(
            [sys.executable, "-m", "pip", "show", "flagtree"],
            capture_output=True, text=True, timeout=10
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Low
Confidence
82% confidence
Finding
The module docstring says it collects environment info needed for package installation decisions and specifically enumerates python version, glibc version, architecture, and GPU vendor. The code also gathers and outputs filesystem free space, which is not mentioned in that description and expands the script's behavior beyond the stated set of collected attributes.

Static analysis

No suspicious patterns detected.