Back to skill

Security audit

Douyin Automation

Security checks for vulnerabilities and agentic risk

Overview

This Douyin uploader is purpose-aligned but needs review because it can automatically publish to a public account while retaining local login state and launching Chromium with sandboxing disabled.

Install only if you are comfortable with an agent-controlled tool posting to your Douyin account by default. Prefer using --no-publish unless you intentionally want immediate publication, keep the skill directory private, do not commit douyin-cookies.json or chrome-user-data, run it as an unprivileged user, and review/pin dependencies before use.

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)

T09 · Insecure Skill Coding Practices

Error
Location
douyin-uploader.js:400
Finding
Chromium Is Launched with Browser Sandboxing Disabled<![CDATA[ ## Vulnerability Details **File Location**: `douyin-uploader.js`, lines 400–413 **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code ```js const browser = await puppeteer.launch({ headless, slowMo: headless ? 0 : 50, args: [ '--window-size=1400,900', '--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled', '--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream', '--disable-notifications' ], defaultViewport: headless ? { width: 1400, height: 900 } : null, userDataDir: this.userDataDir, ignoreDefaultArgs: ['--enable-automation'] }); ``` ### Technical Analysis The `--no-sandbox` and `--disable-setuid-sandbox` arguments disable Chromium's process sandbox for every browser session created by the Skill. These arguments affect login, session validation, and video upload operations. The browser processes remote active content from Douyin while holding authenticated session cookies and having access to a user-selected local video. Chromium's sandbox is a defense-in-depth boundary intended to constrain a compromised renderer or browser subprocess. Disabling both available sandbox mechanisms substantially increases the consequences of a browser vulnerability. This issue does not itself demonstrate arbitrary code execution. Exploitation requires malicious or compromised remote content and a suitable Chromium vulnerability. Nevertheless, the configuration unnecessarily removes a major security control from a browser that handles sensitive authenticated sessions. ### Attack Path 1. The user invokes login, session validation, or video upload functionality. 2. Puppeteer starts Chromium with both sandbox mechanisms disabled. 3. Chromium loads active content from `creator.douyin.com`. 4. An attacker compromises the remote content path or causes the browser to process content that ...[truncated 1068 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox` and `--disable-setuid-sandbox` from the Puppeteer launch arguments. 2. Run Chromium as a dedicated, unprivileged operating-system user. 3. Ensure the deployment environment supports Chromium user namespaces or its setuid sandbox. 4. For containerized execution, configure namespaces, seccomp, capabilities, and filesystem isolation instead of disabling browser sandboxing. 5. Keep Puppeteer and its bundled Chromium version current through a controlled dependency-review process. 6. Where possible, place the browser process in an additional container or operating-system sandbox with access only to the required upload file and profile directory. 7. Fail safely with an explanatory error if the environment cannot launch Chromium securely, rather than automatically falling back to `--no-sandbox`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
douyin-uploader.js:29
Finding
Persistent Browser Authentication Profile Is Not Explicitly Permission-Hardened<![CDATA[ ## Vulnerability Details **File Location**: `douyin-uploader.js`, lines 29–30 and 400–413 **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code ```js constructor() { this.cookiesPath = path.join(__dirname, 'douyin-cookies.json'); this.userDataDir = path.join(__dirname, 'chrome-user-data'); } ``` ```js const browser = await puppeteer.launch({ headless, slowMo: headless ? 0 : 50, args: [ '--window-size=1400,900', '--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled', '--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream', '--disable-notifications' ], defaultViewport: headless ? { width: 1400, height: 900 } : null, userDataDir: this.userDataDir, ignoreDefaultArgs: ['--enable-automation'] }); ``` The separate cookie file is hardened after it is written: ```js await fs.writeFile(this.cookiesPath, JSON.stringify(cookies, null, 2)); // Restrict cookie file permissions (owner read/write only) await fs.chmod(this.cookiesPath, 0o600).catch(() => { }); ``` No equivalent explicit permission setup or verification is applied to `chrome-user-data`. ### Technical Analysis The Skill uses a persistent Chromium user-data directory under the project directory. Chromium profiles can contain cookies, authentication tokens, browsing state, cached responses, local storage, and other account-related data. Although `douyin-cookies.json` is changed to mode `0600`, the profile directory is not explicitly created with mode `0700`, and its ownership and permissions are not checked before Chromium uses it. Protection therefore depends on the process umask, project-directory permissions, operating-system defaults, and any pre-existing directory at that path. The persistent profile also expands the amount of authentication state retained on disk. This is unnecessary if the explici ...[truncated 1488 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an ephemeral Chromium profile created with `fs.mkdtemp()` in a private directory and remove it after every run. 2. If persistence is required, create `chrome-user-data` explicitly with mode `0700` before launching Chromium. 3. Verify that the profile path: - Is a directory rather than a symbolic link. - Is owned by the current user. - Is not group-readable, group-writable, or world-accessible. 4. Apply restrictive permissions recursively to sensitive profile files where supported. 5. Store reusable authentication material in an operating-system credential store instead of plaintext browser-profile files where practical. 6. Document that the profile contains sensitive authentication state and must not be committed, archived, or shared. 7. Add `douyin-cookies.json` and `chrome-user-data/` to `.gitignore`. 8. Retain the existing `0600` cookie-file protection, but handle `chmod` failures explicitly rather than silently suppressing them. 9. Provide a configurable storage location outside the project source directory, such as a private per-user application-data directory. ]]>

T08 · Insecure Dependencies

Warning
Location
package.json:31
Finding
Dependency Installation Is Not Reproducibly Locked<![CDATA[ ## Vulnerability Details **File Location**: `package.json`, lines 31–33; installation instructions in `SKILL.md`, lines 68–74 **Vulnerability Type**: `T08: Insecure Dependencies` **Risk Level**: Medium ### Vulnerable Code `package.json`: ```json "dependencies": { "puppeteer": "^23.11.1" } ``` `SKILL.md`: ```markdown First-time setup — install dependencies / 首次使用需要安装依赖: ```bash cd {baseDir} && npm install ``` > **Note / 说明**: Only installs puppeteer, no external repo cloning needed / 仅安装 puppeteer 依赖,无需克隆外部仓库。 ``` No `package-lock.json` is present in the audited project structure. ### Technical Analysis The dependency uses a caret range, allowing npm to select later semver-compatible Puppeteer releases. Without a committed lockfile, the complete transitive dependency graph and package integrity values are not fixed. Two installations of the same audited source can therefore resolve to different third-party code. The documented use of `npm install` reinforces mutable resolution rather than requiring a reviewed lockfile through `npm ci`. Puppeteer installation may also retrieve browser components as part of its normal package installation behavior, increasing the externally supplied code and binary surface. This is a supply-chain hardening issue. The audit did not identify a malicious current package, dependency-confusion name, typosquatted package, or unsafe non-registry URL. The risk arises because future installation content is not identical to the content reviewed. ### Attack Path 1. An attacker compromises a permitted future package release, a transitive dependency, a registry account, or an associated browser distribution channel. 2. The compromised version remains compatible with the declared `^23.11.1` range or is selected transitively. 3. A user follows `SKILL.md` and runs `npm install`. 4. npm resolves and downloads dependency content that was not represented in the audited project. 5. Malicious lifecycle code may execute during ...[truncated 893 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin Puppeteer to an exact reviewed version rather than a caret range. 2. Generate and commit a reviewed `package-lock.json`. 3. Change installation instructions from `npm install` to `npm ci`. 4. Verify that lockfile entries contain expected registry sources and integrity hashes. 5. Review Puppeteer lifecycle scripts and browser-download behavior before upgrades. 6. Use a controlled registry or dependency proxy where available. 7. Run package installation as an unprivileged user in an isolated build environment. 8. Add automated dependency scanning and update review to the release process. 9. Re-audit dependency and browser changes before updating the lockfile. 10. Consider separating dependency installation from runtime and distributing a reproducibly built, verified artifact. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'shell' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code saves live Douyin session cookies to a local JSON file, creating a reusable bearer token for account access if the file is stolen by another local user, malware, or a later-compromised process. Although permissions are tightened to 0600, there is no explicit just-in-time user consent or strong protection such as encryption or OS credential storage, so session theft remains plausible.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The uploader proceeds to click the publish button automatically whenever autoPublish is not set to false, without a final confirmation step showing the exact content being released. Because publishing is an externally visible, hard-to-reverse action, automation mistakes, bad inputs, or misuse by another caller can cause unintended public posting from the user's account.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The code presents natural-language user interaction text such as SMS verification notices and input prompts only in Chinese. This imposes a fixed language on users without opt-in or a locale-selection mechanism, which matches the policy's language/locale violation criteria.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This code includes natural-language strings in Chinese for the script description and usage, indicating a fixed language choice. The file does not offer any language selection or explain a justified region-specific requirement, which can violate language/locale policy requirements.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The natural-language description prominently presents the skill as a Douyin-specific uploader and includes only Chinese-language wording for its user-facing capability summary. This may indicate a locale/language constraint without any explicit opt-in or alternative language choice, which can conflict with language/locale policy expectations.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"manage": "node scripts/manage.js"
  },
  "dependencies": {
    "puppeteer": "^23.11.1"
  }
}
Confidence
88% confidence
Finding
Using a caret range for puppeteer allows installation of newer dependency versions that were not explicitly reviewed with this skill, which weakens build reproducibility and can unexpectedly introduce vulnerable or breaking releases. In an automation skill that drives a browser and may handle authenticated sessions, dependency drift modestly increases supply-chain risk.

Unverifiable Dependency: puppeteer has 1 known advisory(ies) (CVE-2019-5786 (Use-After-Free in puppeteer)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The file’s natural-language strings present the skill exclusively in Chinese (for example, the title and usage comment) without offering a language choice or documenting that the script is intentionally region-specific. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The file includes Chinese-only natural-language documentation for the script title, usage, and commands. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present here.

Static analysis

No suspicious patterns detected.