Back to skill

Security audit

Douyin Automation

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its Douyin automation purpose, but its setup process uses developer credentials and unverified downloaded code in ways users should review before installing.

Review this skill before installing. It can publish and reply from a logged-in Douyin account, create scheduled automation, start local services, use a persistent Chrome profile, send cover-generation prompts to an external API, clone unpinned GitHub code, install downloaded dependencies, and automatically use GitHub credentials. Prefer running only in an isolated environment with a dedicated browser profile and account, inspect the cloned repositories first, avoid exposing GitHub tokens, and use dry-run until you are comfortable with the posting behavior.

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/setup.py:59
Finding

Unpinned Remote Code Is Downloaded, Installed, and Executed

Content
View full analysis
1 else ""} {auth_url} "{dest}"', timeout=120) if ok: return True, out # Fallback: try without auth (public repo) if token: ok2, out2 = run(f'git clone {"--depth 1" if depth > 1 else ""} {url} "{dest}"', timeout=120) return ok2, out2 return ok, out ``` ```python ok, out = git_clone_with_auth(BACKEND_REPO, str(dest.parent)) if ok: # Rename if cloned as douyin-agent-master directly actual = home / "douyin-agent-master" if actual.is_dir() and not dest.is_dir(): dest = actual print(f" [OK] Cloned to: {dest}") project = dest ``` ```python ok, out = git_clone_with_auth( "https://github.com/HNC87/douyin-automation-skill.git", str(ct_dest.parent / "douyin-automation-skill") ) if ok: # Creator tools are in the skill repo src = ct_dest.parent / "douyin-automation-skill" / "assets" if src.exists(): import shutil ct_dest.mkdir(parents=True, exist_ok=True) for f in src.iterdir(): if f.suffix in [".mjs", ".js"]: shutil.copy(f, ct_dest / f.name) print(f" [OK] Copied to: {ct_ ...[truncated 4290 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup.py:37
Finding

GitHub Tokens Are Harvested and Embedded in Shell Commands

Content
View full analysis
/dev/null") if ok and out.strip(): return out.strip() # Check environment for env in ["GITHUB_TOKEN", "GH_TOKEN"]: t = os.environ.get(env, "") if t: return t # Check git credential store cfg = os.path.expanduser("~/.git-credentials") if Path(cfg).exists(): content = Path(cfg).read_text() m = re.search(r"https://([^:]+):([^@]+)@", content) if m: return m.group(2) return None ``` ```python def git_clone_with_auth(url, dest, depth=1): """Clone using auth token if available.""" token = find_git_auth() if token: auth_url = url.replace("https://", f"https://{token}@") else: auth_url = url # Try with auth first ok, out = run(f'git clone {"--depth 1" if depth > 1 else ""} {auth_url} "{dest}"', timeout=120) if ok: return True, out # Fallback: try without auth (public repo) if token: ok2, out2 = run(f'git clone {"--depth 1" if depth > 1 else ""} {url} "{dest}"', timeout=120) return ok2, out2 return ok, out ``` ### Technical Analysis The setup searches for GitHub credentials through three separate mechanisms: the GitHub CLI, environment variables, and the plaintext Git credential store. I ...[truncated 2818 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior centers on Douyin automation, but the analyzed behavior also includes remote code cloning and possible access to GitHub credentials from local sources without prominently declaring that credential handling. That mismatch is dangerous because users may approve a marketing/automation skill without realizing it can touch developer credentials and import arbitrary remote code into their environment.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

Using subprocess.run with shell=True creates a general tool-parameter abuse primitive because any interpolated parameter can alter shell parsing and execute unintended commands. In this setup script, commands are built from variables including URLs, destinations, and user-provided paths, and the script is designed to run package installation and git operations on the user's machine, making exploitation potentially severe.

Content

Scanner excerpt · scripts/setup.py (reported line 24)May include surrounding context.

python
def run(cmd, cwd=None, timeout=60, check=False):
    """Run shell command, return (success, stdout+stderr)."""
    try:
        r = subprocess.run(
            cmd, shell=True, cwd=cwd,
            capture_output=True, text=True, timeout=timeout
        )

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

Directly reading ~/.git-credentials is credential access behavior and exposes plaintext or recoverable Git secrets to the script. In a setup utility for public repo cloning, this is disproportionate and creates unnecessary risk that tokens could be exfiltrated, mishandled, or leaked through command execution and diagnostic output.

Content

Scanner excerpt · scripts/setup.py (reported line 52)May include surrounding context.

python
return t

    # Check git credential store
    cfg = os.path.expanduser("~/.git-credentials")
    if Path(cfg).exists():
        content = Path(cfg).read_text()
        m = re.search(r"https://([^:]+):([^@]+)@", content)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares no explicit tool scope even though the instructions clearly require shell execution, filesystem reads/writes, environment access, and network operations. In a skill that performs installation, cloning, dependency setup, and service startup, missing permission declarations prevents informed consent and weakens containment around powerful actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill can perform real posting and automated comment replies on the user's authenticated Douyin account, but the description does not present this as a clear operational risk. In the context of social-media automation tied to a logged-in browser session and cron scheduling, insufficient warning increases the chance of accidental unauthorized posting, spam behavior, account penalties, or reputational harm.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation instructs users to export platform comments and process them automatically, but it does not warn that comments and usernames are user data that may be stored locally, queried from SQLite, and reused in downstream automation. In this skill’s context, that omission is security-relevant because the workflow is explicitly designed for large-scale automated collection and handling of third-party content, increasing the chance of privacy misuse, overcollection, or retention without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file provides direct instructions for automatically posting replies from a generated plan, but it does not clearly warn that the tool will publish public responses under the user’s logged-in account. In an automation skill for Douyin operations, this is more dangerous than generic scripting because it enables unattended account actions that can cause reputational harm, accidental spam, policy violations, or misuse if the reply plan is incorrect or tampered with.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/cover-ai.md (reported line 13)May include surrounding context.

md
## Qenda API

- 端点:`https://api.ai6700.com/api/v1/media/generate`
- 模型:`wan2.7-image`
- 同步等待,最长 120s(轮询每 5s 一次,共 24 次)
- 输出尺寸:9:16(竖版抖音封面)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The entire publishing specification is written as mandatory Chinese-language output guidance for titles,正文, tags, and platform publishing behavior, with no indication that the user can choose another language or locale. This creates a natural-language locale policy concern because the skill appears to enforce a specific language by default rather than offering an explicit opt-in or alternative.

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 · scripts/run-pipeline.py (reported line 68)May include surrounding context.

python
print()

    start = time.time()
    result = subprocess.run(cmd, cwd=str(Path(orchestrator).parent))
    duration = round(time.time() - start)

    print()

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

The helper wraps subprocess.run with shell=True and accepts arbitrary command strings, which makes every caller vulnerable to shell metacharacter injection if any part of the command is influenced by user input, file paths, environment data, or repository URLs. In this script, manual path input and computed clone/install commands are interpolated into shell strings, so the setup context increases risk because the script is intended to run on developer machines with local credentials and package managers available.

Content

Scanner excerpt · scripts/setup.py (reported line 24)May include surrounding context.

python
def run(cmd, cwd=None, timeout=60, check=False):
    """Run shell command, return (success, stdout+stderr)."""
    try:
        r = subprocess.run(
            cmd, shell=True, cwd=cwd,
            capture_output=True, text=True, timeout=timeout
        )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The setup script proactively harvests GitHub credentials from gh auth, environment variables, and ~/.git-credentials, then injects the token into clone URLs. This is dangerous because it accesses sensitive credentials without explicit consent and may expose them through process arguments, logs, shell history, error messages, or downstream tooling; in a bootstrap script that clones external code, credential access is especially suspicious and unnecessary for public repositories.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script accesses multiple local credential sources with no warning, consent, or explanation to the user. Even if the goal is convenience, silent credential collection violates least surprise and increases the chance of secret leakage or misuse on the host system.

Content

No source excerpt is available for this finding.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
70% confidence
Finding

Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Content

Scanner excerpt · scripts/setup.py (reported line 117)May include surrounding context.

python
"""Check if Chrome with remote debugging is accessible."""
    import urllib.request
    try:
        r = urllib.request.urlopen(f"http://localhost:{port}/json", timeout=3)
        data = json.loads(r.read())
        return True, f"Chrome CDP active (port {port}), {len(data)} tabs"
    except Exception:

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
70% confidence
Finding

Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Content

Scanner excerpt · scripts/setup.py (reported line 128)May include surrounding context.

python
"""Check if Chrome with remote debugging is accessible."""
    import urllib.request
    try:
        r = urllib.request.urlopen(f"http://localhost:{port}/json", timeout=3)
        data = json.loads(r.read())
        return True, f"Chrome CDP active (port {port}), {len(data)} tabs"
    except Exception:

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/setup.py (reported line 151)May include surrounding context.

python
lines = [
        "# Douyin Automation Configuration",
        "",
        f"> Auto-generated by setup.py on {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M')}.",
        "> Run `python scripts/setup.py` to reconfigure.",
        "",
        "```json",

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 · scripts/start-backend.py (reported line 113)May include surrounding context.

python
return True, " ".join(args)

    try:
        subprocess.Popen(
            args,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This subprocess call builds a single command string from configuration-derived paths and passes it to subprocess.Popen. On POSIX systems, supplying a string without explicit argument splitting can cause unsafe or unreliable execution behavior, and because backend_dir originates from CONFIG.md, a maliciously modified config can redirect execution to attacker-controlled code, causing arbitrary local code execution when the script starts the backend.

Content

Scanner excerpt · scripts/start-backend.py (reported line 141)May include surrounding context.

python
cmd = f'"{python}" "{main_py}"'

    try:
        subprocess.Popen(
            cmd,
            cwd=str(Path(backend_dir).parent),
            stdout=subprocess.DEVNULL,

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/status-check.py (reported line 89)May include surrounding context.

python
def main():
    print("=== Douyin Automation Status ===")
    print(f"OS: {__import__('os').name} / {__import__('sys').platform}")
    print()

    config = load_config()

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The document title and all instructional content are written in Chinese, with no indication that the user can choose another language or that the skill is intentionally limited to a Chinese-speaking context. Under the policy, language constraints should be opt-in or explicitly justified when they restrict accessibility.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.