Back to skill

Security audit

Stata Econ Workflow Publish

Security checks for vulnerabilities and agentic risk

Overview

This Stata research workflow is mostly purpose-aligned, but it includes persistent agent-memory and Git-hook behaviors that need careful review before installation.

Install only in a trusted Stata research repository. Review and remove or constrain the automatic MEMORY.md/TOOLS.md/CLAUDE.md learning behavior, pin external tooling versions before running uvx/npm/pip commands, and do not install the pre-commit hook unless you have checked what it will execute and are comfortable with persistent Git-hook behavior.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (5)

T02 · Agent Memory Poisoning

Error
Location
references/merge-protocol.md:30
Finding

Unvalidated User Corrections Can Be Written into Persistent Agent State

Content
View full analysis

Vulnerability Details

File Location: references/merge-protocol.md, lines 30-45
Vulnerability Type: Persistent instruction poisoning
Risk Level: High

Vulnerable Instruction Snippet

The following is an English rendering of the operative instructions:

markdown
When the user says "incorrect," the following actions are mandatory:
1. Briefly acknowledge the error.
2. Immediately record it in MEMORY.md with a [LEARN] tag.
3. Correct the corresponding error in the do-file, if present.
4. Apply the correction continuously in similar future situations.

MEMORY.md entry format:

## [LEARN] 2025-12-01 — Standard-error clustering level
- Context: DiD analysis with panel data
- Error: Clustered at the individual rather than state level
- Correction: Use cluster(state_id) rather than cluster(id)
- Reason: Treatment is correlated within states

A related instruction appears in references/workflow-quickref.md, lines 102-104:

markdown
When the user provides a correction, record it in MEMORY.md, TOOLS.md, or CLAUDE.md.

Technical Analysis

The workflow directs the agent to persist user-provided corrections without requiring validation, sanitization, or explicit approval of the exact stored content. It also permits writes to CLAUDE.md and TOOLS.md, which may contain durable behavioral or tool-use instructions loaded in later sessions.

A malicious user could present an attacker-controlled behavioral rule as a correction. If the rule is copied into persistent state, it can influence future sessions after the original interaction has ended. The risk is especially significant for CLAUDE.md, because that file may function as project-level agent instructions rather than as a passive research log.

Attack Path

  1. An attacker tells the agent that an existing workflow rule is “incorrect.”
  2. The attacker embeds a new behavioral directive in the purported correction.
  3. The Skil ...[truncated 712 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove all automatic writes to CLAUDE.md, TOOLS.md, and other agent instruction files.
  2. Store lessons only in a dedicated passive file such as quality_reports/proposed-learnings.md.
  3. Require explicit user confirmation of the exact sanitized entry before writing it.
  4. Restrict entries to project facts, such as variable definitions or validated statistical conventions.
  5. Reject content containing tool directives, role changes, security-policy changes, external commands, secrets, or instructions for future sessions.
  6. Add provenance fields recording who proposed the correction, when it was validated, and what evidence supports it.
  7. Treat persistent learning files as untrusted data when loaded; never interpret their contents as higher-priority instructions.

T08 · Insecure Dependencies

Error
Location
SKILL.md:81
Finding

Unpinned Third-Party Packages Are Retrieved and Executed

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 81-94
Vulnerability Type: Unpinned executable dependencies
Risk Level: High

Vulnerable Instruction Snippet

bash
# Check availability
uvx stata-mcp --usable

# Execute a do-file
uvx stata-mcp tool do dofiles/02_construct/main.do --log-file-name main

# Install a package
uvx stata-mcp tool ado-install reghdfe --source ssc

# Read a log
uvx stata-mcp tool read-log logs/02_construct_main.log --output-format dict

Additional unpinned installation instructions appear in templates/CONTRIBUTING-FOR-FORKERS.md, lines 8-15:

bash
npm install -g @anthropic-ai/claude-code
pip install nbstata
# Alternative:
pip install pystata

Technical Analysis

These commands retrieve and execute the current versions of packages from external registries or package sources. No exact versions, integrity hashes, lockfiles, signed-artifact verification, or publisher-validation procedure is specified.

In particular, uvx stata-mcp may resolve and execute a package dynamically when invoked. Consequently, the code executed by the workflow can change after the Skill itself has been audited. Global npm installation also increases the scope of a compromised dependency because it installs executable tooling at the user environment level.

Attack Path

  1. A package account, registry, distribution channel, or transitive dependency is compromised.
  2. A malicious package version is published under the expected package name.
  3. A user follows the Skill instructions without an exact version constraint.
  4. The package manager resolves and downloads the malicious release.
  5. Package installation hooks or the invoked command execute attacker-controlled code with the user's privileges.

Impact Assessment

A compromised package can generally obtain the same privileges as the user running npm, pip, or uvx. This may permit arbitrary command exec ...[truncated 340 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every dependency to an audited exact version.
  2. Use lockfiles and integrity hashes where supported.
  3. Replace dynamic uvx package execution with execution from a reviewed, locked environment.
  4. Verify package publishers, source repositories, release signatures, and expected checksums.
  5. Avoid global npm installation unless it is explicitly required and approved.
  6. Run package installation in an isolated virtual environment or container with minimal filesystem access.
  7. Require explicit user confirmation before network retrieval or package installation.
  8. Document a dependency-update review process so new versions are audited before adoption.

T06 · System Persistence

Error
Location
templates/CONTRIBUTING-FOR-FORKERS.md:33
Finding

Template Overwrites and Installs a Persistent Git Pre-Commit Hook

Content
View full analysis

Vulnerability Details

File Location: templates/CONTRIBUTING-FOR-FORKERS.md, lines 33-40
Vulnerability Type: Repository-level execution persistence
Risk Level: High

Vulnerable Instruction Snippet

bash
cat > .git/hooks/pre-commit <<'EOF'
#!/bin/bash
python scripts/check_data_safety.py --staged $(git diff --cached --name-only)
EOF
chmod +x .git/hooks/pre-commit

Technical Analysis

The instructions overwrite .git/hooks/pre-commit without checking whether a hook already exists, preserving its contents, or requesting confirmation. Once installed, the hook executes automatically whenever a commit is attempted, surviving the Skill invocation itself.

The hook delegates execution to scripts/check_data_safety.py, but that script is absent from the audited directory structure. This can cause commit failures immediately. If a file with that name is later introduced or modified, it will be executed automatically during commits.

The unquoted command substitution also expands staged filenames into separate shell arguments. Although this snippet does not directly invoke eval, robust handling should use a null-delimited filename protocol to avoid ambiguity involving whitespace, newlines, or option-like filenames.

Attack Path

  1. A user follows the template and overwrites the repository's existing pre-commit hook.
  2. The installed hook remains active for subsequent Git commits.
  3. An attacker introduces or modifies scripts/check_data_safety.py through an untrusted branch, archive, dependency update, or repository change.
  4. The user attempts a commit.
  5. Git automatically executes the attacker-controlled Python script with the user's privileges.

An immediate denial-of-service path also exists because the referenced script is missing: every attempted commit may fail until the hook is removed or the script is added.

Impact Assessment

The hook can execute arbitrary Python ...[truncated 391 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not overwrite .git/hooks/pre-commit directly.
  2. Ship the referenced verification script and audit it before recommending hook installation.
  3. Use a reviewed framework such as pre-commit with a version-controlled configuration and pinned revisions.
  4. Require explicit user approval before installing any persistent hook.
  5. Detect an existing hook and either abort or safely chain it after user review.
  6. Resolve the verifier from a trusted location and verify that it is a regular file within the expected repository.
  7. Use python3 or a controlled interpreter from a pinned environment.
  8. Pass staged filenames through a null-delimited interface instead of unquoted command substitution.
  9. Provide documented uninstall and recovery instructions.

T09 · Insecure Skill Coding Practices

Warning
Location
references/reproduction-protocol.md:63
Finding

Reproduction Logs Collect Unnecessary Local Account Identity

Content
View full analysis

Vulnerability Details

File Location: references/reproduction-protocol.md, lines 63-80
Vulnerability Type: Plaintext disclosure of local environment metadata
Risk Level: Medium

Vulnerable Instruction Snippet

stata
* Stata version and flavor
display "Stata version: " c(stata_version)
display "Flavor: " c(flavor)
display "OS: " c(os)
display "Username: " c(username)
display "Date: " c(current_date) " " c(current_time)

* Key user-written commands
which reghdfe
which esttab
which ivreg2
which boottest

Technical Analysis

Capturing the Stata version and package versions is relevant to reproducibility. Recording c(username), however, collects local account identity without a demonstrated analytical need. The protocol writes this information to logs/00_master_environment.log, creating a durable plaintext artifact.

Research logs are frequently shared with collaborators, included in reproduction archives, uploaded to issue trackers, or accidentally committed. The project recommends ignoring logs, but ignore rules are not an access-control boundary and can be bypassed.

Attack Path

  1. The user runs the reproduction pipeline.
  2. Stata writes the local username and environment metadata to the environment log.
  3. The log is shared, archived, force-added to Git, or included in a support bundle.
  4. A recipient obtains the user's local account name and system metadata.
  5. The information can be used for identity correlation, targeted phishing, or more accurate path and account-name guessing.

Impact Assessment

This issue does not itself grant additional system privileges or provide direct code execution. It exposes personally identifying and operational metadata available to the current Stata process. The scope is limited to recorded environment fields, but the information can assist social engineering and later attacks, particularly when account names are reused across sys ...[truncated 5 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove display "Username: " c(username) from the environment snapshot.
  2. Collect only information necessary to reproduce results, such as Stata version, flavor, command versions, and relevant package revisions.
  3. Redact usernames and home-directory fragments before logs are shared.
  4. Add a warning that environment logs may contain machine-specific metadata.
  5. Keep logs outside version control and add an automated staged-file check as defense in depth.
  6. Provide an explicit opt-in flag for any additional diagnostic metadata.

T09 · Insecure Skill Coding Practices

Error
Location
hooks/pre-commit-verify.py:43
Finding

Pre-Commit Verifier Executes a Python Program Selected by an Untrusted Project Root

Content
View full analysis

Vulnerability Details

File Location: hooks/pre-commit-verify.py, lines 43-72
Vulnerability Type: Untrusted path used as an executable program
Risk Level: High

Vulnerable Code Snippet

python
def main():
    if len(sys.argv) < 2:
        root = os.getcwd()
    else:
        root = sys.argv[1]

    log_dir = os.path.join(root, 'logs')
    dofiles = glob.glob(os.path.join(root, 'dofiles', '**', '*.do'), recursive=True)
    dofiles += glob.glob(os.path.join(root, 'dofiles', '**', '*.py'), recursive=True)

    errors = []
    warnings = []

    for df in sorted(dofiles):
        path_issues = check_hardcoded_paths(df)
        errors.extend(path_issues)

        if os.path.isdir(log_dir):
            log_issue = check_log_freshness(df, log_dir)
            if log_issue:
                warnings.append(log_issue)

    qc = os.path.join(root, 'scripts', 'quality_score.py')
    if os.path.exists(qc):
        print('Running quality score...')
        r = subprocess.run(
            ['python', qc] + dofiles,
            capture_output=True,
            text=True
        )

Technical Analysis

The command-line argument directly controls root, and the script constructs the executable Python file path as root/scripts/quality_score.py. It validates only that the path exists. It does not verify that the root is trusted, canonicalize it, reject symbolic links, confirm repository ownership, or ensure that the scorer is the audited script shipped with the hook.

The subprocess call correctly avoids shell interpolation by using an argument array, so conventional shell metacharacter injection is not present. Nevertheless, arbitrary code execution is possible by controlling the file located at the derived path.

The use of the generic python executable also depends on the caller's PATH, allowing interpreter ambiguity or local tool spoofing in hostile environments.

...[truncated 958 chars]

Remediation
View remediation

Remediation Suggestions

  1. Resolve the trusted scorer relative to the hook's own audited location rather than a caller-controlled root.
  2. Canonicalize paths with Path.resolve() and verify that expected files remain within the trusted directory.
  3. Reject symbolic links for executable verifier files or verify their resolved destinations.
  4. Validate that the supplied project root is the expected Git repository before processing it.
  5. Import trusted scoring functions directly rather than launching a project-controlled Python file.
  6. If subprocess isolation is required, invoke sys.executable instead of the ambiguous python command.
  7. Run the scorer with a minimal environment and least-privilege filesystem access.
  8. Clearly warn users never to run the verification hook against untrusted repositories.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (40)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% 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).

Content

Scanner excerpt · templates/CONTRIBUTING-FOR-FORKERS.md (reported line 50)May include surrounding context.

git add -f data/raw/test_blocker.dta # -f because .gitignore blocks it git commit -m "test" # should be REJECTED by the hook git reset HEAD data/raw/test_blocker.dta rm data/raw/test_blocker.dta

text

---

Rp1

Medium
Category
MCP Rug Pull
Confidence
65% confidence
Finding

uvx/uv tool run commands without ==version create a rug-pull risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill explicitly instructs reading files and invoking shell-based commands, but it declares no tool scope or allowed-tools boundary. In an agent environment, this increases the chance of over-broad file access or command execution beyond what is necessary for the Stata workflow, especially because the skill is designed to run local do-files and inspect logs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest description and invocation guidance are written entirely in Chinese and present the skill as a Chinese-language workflow, but do not state that users may choose another language. Under the policy, language-specific behavior should either be optional or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation description says the skill triggers when the user mentions any of a very long keyword list, and that list includes generic terms such as "study," "paper," "template," "workflow," "quality," "verify," and "log." These overlap with ordinary conversation and many non-Stata tasks, making the activation scope ambiguous despite the brief exclusion note on L015.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The skill recommends executing uvx stata-mcp without pinning a specific version or immutable source. This creates a supply-chain risk: future or compromised upstream releases could change behavior and execute unintended code when the agent follows the documented workflow.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

This unpinned uvx stata-mcp invocation is used for running do-files, which is a sensitive execution path. If the referenced MCP package is replaced or updated maliciously, it could run arbitrary code under the guise of Stata job execution.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The skill uses an unpinned uvx stata-mcp command to install packages, compounding supply-chain exposure because both the MCP tool and downstream package operations may vary over time. This can introduce unreviewed code into the analysis environment.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

Reading logs via an unpinned MCP server is less sensitive than code execution, but still relies on a mutable external tool that may change behavior unexpectedly. In aggregate with the other uvx stata-mcp usages, it reflects an avoidable trust boundary weakness.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description and the full operating instructions are written in Chinese and present the agent's behavior/output format only in Chinese, with no indication that users may choose another language. This creates a natural-language policy issue under the language/locale rule because the skill appears to require a specific language without explicit user opt-in or documented justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description and the body of the skill are written entirely in Chinese, and the required output template also mandates Chinese section headings. This creates a language/locale constraint without any opt-in, alternative language option, or justification that the skill is region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest description and I/O contract are written entirely in Chinese, which signals a fixed language expectation for the skill. The file does not offer any user opt-in or alternative language choice, so it may violate a language/locale policy requiring user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill metadata and description are written only in Chinese, which effectively constrains interaction language without any user opt-in or locale negotiation. In a multi-language agent environment, this can reduce accessibility, cause user confusion, and make the skill behave inconsistently with user expectations, though it is not a direct code-execution or data-exfiltration risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The mandated output template uses fixed Chinese headings and labels, forcing a specific locale regardless of user preference. This can impair usability, downstream parsing, or review workflows that expect another language, especially in collaborative or international research settings.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest text is written as a Chinese-only role description and says the agent is a professional Chinese+English bilingual proofreader, but it does not explicitly let the user choose language or locale. Under the policy rule, forcing or implying a specific language behavior without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · hooks/pre-commit-verify.py (reported line 71)May include surrounding context.

python
qc = os.path.join(root, 'scripts', 'quality_score.py')
    if os.path.exists(qc):
        print('Running quality score...')
        r = subprocess.run(['python', qc] + dofiles, capture_output=True, text=True)
        if r.returncode != 0:
            warnings.append('Quality score < 80 for some files')
        print(r.stdout[-500:])

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file presents the substantive instructions entirely in Chinese, which can force a specific language on users without opt-in. The policy allows locale-specific constraints only when they are explicitly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The operational instructions, trigger conditions, required phrasing, and examples are presented in Chinese, which effectively forces a specific language for users of the skill. There is no opt-in, alternative language option, or documented reason that this skill must be Chinese-only.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger section activates on very broad situations such as summarizing logs, reports, commit messages, or answering any question containing numeric empirical results. In a research-writing workflow, this can cause the skill to be invoked in many ordinary contexts, increasing the chance of unexpected refusals, workflow hijacking, or over-application of rigid verification gates outside the user's intended scope.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The rule triggers persistence whenever the user says "不对," which is an extremely broad conversational phrase and not a reliable signal of consent or of a durable correction worth storing. In a research-assistant workflow, this can cause accidental capture of user feedback, sensitive context, or transient misunderstandings into long-lived memory, creating privacy and integrity risks in future sessions.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The protocol explicitly requires recording user corrections to MEMORY.md and reviewing session logs regularly, which creates a structured retention channel for natural-language data. In this skill's context—empirical research, replication, logs, and quality review—those notes may contain unpublished results, proprietary data descriptions, reviewer comments, or other sensitive project information that can later be surfaced to unintended contexts or agents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The protocol directs the agent to write to MEMORY.md immediately, but gives no user-facing notice that information will be persisted beyond the current interaction. That creates a data-retention and consent problem: users may reveal research details, errors, identifiers, or unpublished findings without realizing they are being stored in shared project memory.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file contains instructional content exclusively in Chinese, including core operational requirements and examples. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest scope includes both dofiles/**/*.do and the broad data/** path, which can cause the skill to activate on raw or derived data files rather than only on Stata code and workflow artifacts. In a research workflow skill, that overbroad targeting increases the chance of unintended handling of sensitive datasets or irrelevant files, expanding exposure and confusing when the skill should run.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The instruction 使用中文注释以方便理解 is a natural-language policy concern because it requires one language for comments without opt-in or alternatives. The file does not state that the skill is region-specific or allow users to choose another language, so it appears to violate the language/locale policy.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.