Back to skill

Security audit

Douyin Comment Auto Reply

Security checks for vulnerabilities and agentic risk

Overview

The skill’s Douyin reply workflow is coherent, but it needs Review because its browser automation can post from an authenticated account while using unsafe shell-based, unpinned runtime tooling.

Install only if you are comfortable with a review-first Douyin workflow and can harden the executor before using it. Pin or locally install the browser tool, avoid untrusted `--browser-cmd`, URL, selector, or draft inputs, use a separate low-privilege browser profile, and manually review replies before sending public comments.

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

T08 · Insecure Dependencies

Error
Location
scripts/browser_reply_runner.py:22
Finding

Unpinned Third-Party Package Is Downloaded and Executed at Runtime

Content
View full analysis

Vulnerability Details

File Location: scripts/browser_reply_runner.py:22 and SKILL.md:201
Vulnerability Type: Unpinned runtime dependency and supply-chain exposure
Risk Level: High

Vulnerable Code

python
p.add_argument(
    "--browser-cmd",
    default="npx -y agent-browser",
    help="agent-browser command prefix"
)

The documented behavior is:

markdown
This executor defaults to `npx -y agent-browser`, so it can work even if
`agent-browser` is not installed globally yet.

Technical Analysis

The default command uses npx -y to retrieve and execute agent-browser without specifying an audited version, lockfile, or integrity hash. Consequently, the effective code executed by the Skill can change after the project itself has been reviewed.

The -y option suppresses the package installation confirmation, making the download and execution automatic. If the upstream package, package registry, maintainer account, or dependency graph is compromised, malicious code could execute as soon as the browser runner is invoked.

Although the package name does not exhibit obvious typosquatting in the audited files, the absence of version and integrity controls creates a supply-chain vulnerability.

Attack Path

  1. An attacker compromises the published agent-browser package, one of its dependencies, or the associated package-maintainer account.
  2. A new malicious package version is published under the package name used by the runner.
  3. An operator invokes scripts/browser_reply_runner.py using its default configuration.
  4. The runner executes npx -y agent-browser.
  5. npx retrieves and executes the current package version without an interactive confirmation.
  6. The malicious package executes under the operating-system identity of the operator.

Impact Assessment

Malicious dependency code would receive the same local privileges as the operator running the Skill. ...[truncated 381 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin agent-browser to a specifically reviewed version rather than resolving the latest release at runtime.
  2. Add a package manifest and committed lockfile containing integrity metadata.
  3. Install dependencies during a controlled setup phase rather than during reply execution.
  4. Invoke the locally installed, version-locked executable directly.
  5. Enable dependency vulnerability and provenance checks in CI.
  6. Run browser automation in a restricted environment with minimal filesystem access and no unrelated credentials.
  7. Avoid automatic installation flags such as -y for security-sensitive interactive-browser tooling.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/browser_reply_runner.py:6
Finding

Command Injection Through the User-Controlled Browser Command Prefix

Content
View full analysis

Vulnerability Details

File Location: scripts/browser_reply_runner.py:6-8, 22, 40-41, 52-53
Vulnerability Type: OS command injection through shell-based command construction
Risk Level: High

Vulnerable Code

python
def run(cmd: str):
    print(f"$ {cmd}")
    subprocess.run(cmd, shell=True, check=True)
python
p.add_argument(
    "--browser-cmd",
    default="npx -y agent-browser",
    help="agent-browser command prefix"
)
python
open_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} open {shlex.quote(args.url)}"
wait_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} wait --load networkidle"
run(open_cmd)
run(wait_cmd)
python
fill_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} fill {shlex.quote(args.reply_box_selector)} {shlex.quote(reply)}"
click_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} click {shlex.quote(args.submit_selector)}"

Technical Analysis

The runner builds complete shell command strings and passes them to subprocess.run with shell=True. While the session name, URL, selectors, and reply text are protected with shlex.quote, args.browser_cmd is inserted into every command without quoting, parsing, or validation.

As a result, shell control operators embedded in --browser-cmd are interpreted by the operating-system shell. An attacker who can influence this argument through a wrapper, job definition, automation request, or delegated invocation can append arbitrary commands.

Quoting the other parameters does not mitigate this issue because the injection occurs in the unquoted command prefix.

Attack Path

  1. An attacker obtains influence over the arguments used to launch the runner, such as through an automation configuration or an operator copying an untrusted command.
  2. The attacker supplies a --browser-cmd ...[truncated 1073 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove shell=True and pass subprocess arguments as a list.
  2. Represent the browser executable separately from its arguments.
  3. Prefer a fixed executable path rather than accepting an unrestricted command prefix.
  4. If configurability is required, validate the executable against an explicit allowlist and reject shell metacharacters.
  5. Resolve and verify the executable before invocation.
  6. Use a construction such as:
python
subprocess.run(
    [
        browser_executable,
        "--session-name",
        args.session_name,
        "open",
        args.url,
    ],
    shell=False,
    check=True,
)
  1. Add regression tests that pass shell metacharacters through every CLI argument and confirm that they remain literal data.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/browser_reply_runner.py:40
Finding

Dry-Run Mode Still Installs or Executes Browser Tooling and Performs Network Navigation

Content
View full analysis

Vulnerability Details

File Location: scripts/browser_reply_runner.py:40-58
Vulnerability Type: Unsafe dry-run implementation with unexpected external side effects
Risk Level: Medium

Vulnerable Code

python
open_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} open {shlex.quote(args.url)}"
wait_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} wait --load networkidle"
run(open_cmd)
run(wait_cmd)

log = []
for idx, item in enumerate(sendable, 1):
    reply = item.get("public_reply", "").strip()
    if not reply:
        continue
    print(f"[{idx}/{len(sendable)}] replying to: {item.get('comment','')}")
    fill_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} fill {shlex.quote(args.reply_box_selector)} {shlex.quote(reply)}"
    click_cmd = f"{args.browser_cmd} --session-name {shlex.quote(args.session_name)} click {shlex.quote(args.submit_selector)}"
    if args.dry_run:
        print(fill_cmd)
        print(click_cmd)
    else:
        run(fill_cmd)
        run(click_cmd)
        time.sleep(args.wait_ms / 1000)

Technical Analysis

The args.dry_run condition is checked only after the browser open and wait commands have already executed. Therefore, dry-run mode suppresses the fill and click operations but does not suppress external process execution, runtime package installation, browser-session initialization, or navigation to the supplied URL.

This conflicts with the ordinary security expectation that a dry run previews actions without causing external side effects. It is particularly relevant because the default browser command uses npx -y, meaning that a documented dry run can still retrieve and execute third-party code.

Attack Path

  1. An operator follows the documented recommendation to run the browser executor with --dry-run.
  2. The runner constructs the browser open and wait ...[truncated 902 chars]
Remediation
View remediation

Remediation Suggestions

  1. Check args.dry_run before executing any external command.
  2. In dry-run mode, print the open, wait, fill, and click operations without invoking the browser command.
  3. If browser navigation is required for selector validation, expose it through a separately named and explicit option rather than overloading dry-run behavior.
  4. Update the documentation to define precisely which actions each execution mode performs.
  5. Add automated tests verifying that dry-run mode creates no subprocesses and performs no network or browser activity.
  6. Avoid writing a file named as a sent log during dry runs, or clearly mark entries as simulated rather than sent.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

This is a true tool-parameter abuse issue because the script bridges external inputs directly into a shell command that drives a browser automation tool capable of navigation, form filling, and clicking. In the skill context, that is more dangerous than a generic shell wrapper: manipulated parameters can both execute arbitrary local commands and cause unintended actions against the user's Douyin account or any URL supplied to the tool.

Content

Scanner excerpt · scripts/browser_reply_runner.py (reported line 8)May include surrounding context.

python
def run(cmd: str):
    print(f"$ {cmd}")
    subprocess.run(cmd, shell=True, check=True)


def main():

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill instructs users to run local Python scripts and a browser automation flow, but it does not declare any tool scope or permissions boundaries. That creates an authorization gap: an agent or runtime may expose file and shell capabilities more broadly than intended, increasing the chance of unsafe execution or misuse of local resources.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

Using npx -y agent-browser without pinning an exact package version allows whatever package version is currently published to be fetched and executed at runtime. If the package is compromised, replaced, or updated with malicious code, this skill could trigger arbitrary code execution in the user's environment during browser automation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The intent-matching rules and generated reply text are written entirely in Chinese, which effectively constrains the skill to a specific language/locale. Because the file does not offer an opt-in language choice or explain that it is intentionally region- or language-specific, this is a natural-language policy concern under the language/locale rule.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The script builds shell command strings from user-controlled arguments such as --browser-cmd, --url, and selectors, then executes them with subprocess.run(..., shell=True). Although some fields are shell-quoted, the browser command prefix itself is not safely tokenized or allowlisted, so an attacker who can influence arguments can inject arbitrary shell commands and achieve local command execution.

Content

Scanner excerpt · scripts/browser_reply_runner.py (reported line 8)May include surrounding context.

python
def run(cmd: str):
    print(f"$ {cmd}")
    subprocess.run(cmd, shell=True, check=True)


def main():

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

Using "npx -y agent-browser" without a pinned version causes the script to fetch and execute whatever package version is current at runtime. This creates a supply-chain risk: a compromised upstream package, typo-squatted dependency, or breaking update could result in arbitrary code execution on the host running the skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This file contains example user comments exclusively in Chinese, which can imply a fixed language expectation for downstream use. Because there is no accompanying note that the skill is China-specific or that language is configurable, this may violate the policy against forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This JSON file contains canned comment replies entirely in Chinese, implying the skill is configured to respond in a specific language by default. There is no indication in the file that users can opt into another language or that the Chinese-only behavior is required for a documented region-specific purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This JSON example hard-codes all user comments and suggested replies in Chinese, implying the skill operates in a single language without offering user opt-in or documenting a region-specific constraint. That is a natural-language policy concern because it can force a locale/language choice on users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The plan explicitly requires storing a sent log with timestamps and original comment text, which can retain user-generated content that may include personal data, sensitive disclosures, or contact information. In the context of semi-automated social media engagement, this creates unnecessary data retention risk if the log is not minimized, disclosed, access-controlled, and subject to deletion rules.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This JSON template contains user-facing reply text entirely in Chinese, including comments and response drafts. Because the file provides no indication that the skill is region-specific or that users can opt into another language, it may violate the language/locale policy requiring choice or documented justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.