Back to skill

Security audit

AutoGitHub

Security checks for vulnerabilities and agentic risk

Overview

This GitHub management skill is mostly aligned with its stated purpose, but it handles powerful GitHub tokens and CI/CD automation in ways that need careful review before installation.

Install only if you are comfortable giving this tool GitHub repository authority. Prefer a fine-grained PAT limited to specific repositories and permissions, do not pass secrets in shell history, protect or avoid the plaintext config file, review generated workflows before committing them, and fix the command-injection and mutable-action template issues before using it in CI/CD or production deployment workflows.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate-changelog.js:27
Finding
Shell Command Injection Through the Changelog --since Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-changelog.js:27-35`, with attacker-controlled input assigned at `scripts/generate-changelog.js:318-319` **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```javascript getGitLog(sinceTag = null) { try { let command = 'git log --pretty=format:"%H|%an|%ad|%s" --date=short'; if (sinceTag) { command += ` ${sinceTag}..HEAD`; } const output = execSync(command, { encoding: 'utf8' }); ``` The value is obtained directly from the command line: ```javascript if (arg === '--since' && args[index + 1]) { options.sinceTag = args[index + 1]; } ``` ### Technical Analysis The `--since` value is concatenated into a shell command and passed to `execSync()` as a string. String-based `execSync()` invokes a command shell, so shell metacharacters in `sinceTag` are interpreted as commands rather than as part of a Git revision. No quoting, ref validation, or argument separation prevents an input containing command separators, substitutions, redirections, or similar syntax from changing the executed command. ### Attack Path 1. An attacker convinces a user or automation process to run the changelog generator with an attacker-controlled `--since` value. 2. The CLI parser stores the supplied text in `options.sinceTag`. 3. `getGitLog()` appends the text directly to the `git log` command. 4. `execSync()` passes the resulting string to a shell. 5. Shell syntax embedded in the value executes with the privileges of the Node.js process. For example, a value structurally resembling `valid-tag; attacker-command; #` would terminate the intended Git command and introduce an additional shell command. ### Impact Assessment Successful exploitation provides arbitrary local command execution under the account running the script. The attacker could read or modify repository files, access environment variables and locally readable credentials, alter gener ...[truncated 165 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid invoking a shell. Pass every Git argument separately: ```javascript const { execFileSync } = require('child_process'); const args = [ 'log', '--pretty=format:%H|%an|%ad|%s', '--date=short' ]; if (sinceTag) { args.push(`${sinceTag}..HEAD`); } const output = execFileSync('git', args, { encoding: 'utf8', shell: false }); ``` Additionally: 1. Validate the supplied revision using a strict expected format. 2. Verify that it resolves with a separate non-shell Git call such as `git rev-parse --verify`. 3. Reject values beginning with `-` to prevent Git option injection. 4. Run the generator with the minimum filesystem and credential access required. 5. Add tests covering shell metacharacters, option-like values, malformed refs, and traversal attempts. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
templates/github-actions/deploy-workflow.yml:34
Finding
GitHub Actions Shell Injection Through workflow_dispatch Version Input<![CDATA[ ## Vulnerability Details **File Location**: `templates/github-actions/deploy-workflow.yml:34-36` **Vulnerability Type**: CI workflow command injection **Risk Level**: High ### Vulnerable Code ```yaml - name: Determine version id: version run: | if [[ "${{ github.event.inputs.version }}" != "" ]]; then echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT elif [[ "${{ github.ref }}" == refs/tags/* ]]; then echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT else echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT fi ``` ### Technical Analysis GitHub expression substitution occurs before the generated script is executed. The manually supplied `version` input is embedded directly into shell source code in two locations. An input containing quote characters and shell syntax can break out of the intended quoted value and modify the script executed by the runner. Quoting the expression as `"${{ ... }}"` does not make it safe because the untrusted value is inserted into the script before Bash parses the quotes. ### Attack Path 1. A user with permission to dispatch the workflow supplies a crafted `version` input. 2. GitHub substitutes that value directly into the `run` script. 3. The crafted value terminates or changes the intended shell expression. 4. Bash interprets the injected syntax as runner commands. 5. The commands execute within the `prepare` job's security context. ### Impact Assessment Exploitation provides command execution on the GitHub-hosted runner. The attacker could modify job outputs, inspect the checkout, make network requests, and access credentials available to the `prepare` job. Because `actions/checkout` uses persisted Git credentials by default, the effective repository impact also depends on the workflow token's configured default permissions. This does not automatically expose environment secrets assigned only to later deployment jobs, but poisoned output ...[truncated 63 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Pass expression values through environment variables instead of inserting them into shell source: ```yaml - name: Determine version id: version env: INPUT_VERSION: ${{ github.event.inputs.version }} run: | if [[ -n "$INPUT_VERSION" ]]; then if [[ ! "$INPUT_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([+-][A-Za-z0-9.-]+)?$ ]]; then echo "Invalid version format" >&2 exit 1 fi printf 'version=%s\n' "$INPUT_VERSION" >> "$GITHUB_OUTPUT" elif [[ "$GITHUB_REF" == refs/tags/* ]]; then printf 'version=%s\n' "${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" else printf 'version=%s\n' "$(git describe --tags --always)" >> "$GITHUB_OUTPUT" fi ``` Also: 1. Declare restrictive workflow and job-level `permissions`. 2. Configure checkout with `persist-credentials: false` where pushes are unnecessary. 3. Restrict who may dispatch production workflows. 4. Require protected GitHub environments and reviewers for production. 5. Treat all event properties and manual inputs as untrusted data. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
github-cli.js:34
Finding
GitHub Personal Access Token Exposed Through Command-Line and Plaintext Storage<![CDATA[ ## Vulnerability Details **File Location**: `github-cli.js:13-14`, `github-cli.js:34-38`, and `github-cli.js:492-499` **Vulnerability Type**: Insecure credential handling **Risk Level**: Medium ### Vulnerable Code ```javascript constructor() { this.configPath = path.join(process.cwd(), '.github-manager.json'); this.config = this.loadConfig(); ``` ```javascript saveConfig() { try { fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2)); console.log('Configuration saved successfully.'); } catch (error) { console.error('Error saving config:', error.message); } } ``` ```javascript if (args.config) { if (args.token && args.username) { manager.config.github = { token: args.token, username: args.username, defaultRepo: args['default-repo'] || null }; manager.saveConfig(); ``` The documented setup also places the token on the command line: ```bash node github-cli.js config --token YOUR_GITHUB_TOKEN --username YOUR_USERNAME ``` ### Technical Analysis The GitHub PAT is accepted as a command-line argument and written in plaintext JSON. Command-line secrets can be retained in shell history and may be visible through process-inspection facilities while the command is running. `fs.writeFileSync()` is called without an explicit restrictive mode. The resulting permissions depend on the user's umask and any pre-existing file permissions. The project documentation tells users to add the configuration file to `.gitignore`, but the audited directory structure does not include a root `.gitignore`. The same token is used for both read-only and mutating functionality. The README recommends a classic token with broad `repo` scope, which is greater than necessary for operations such as reading public PR metadata or generating reports. ### Attack Path 1. A user follows the documented command and enters a PAT directly in the shell. 2. The complete command may remain in shell history or be visible i ...[truncated 774 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept PATs through normal command-line arguments. 2. Read credentials from a hidden interactive prompt, an environment variable supplied securely by the caller, the operating-system keychain, or an existing GitHub CLI credential provider. 3. Create the configuration file with owner-only permissions: ```javascript fs.writeFileSync( this.configPath, JSON.stringify(this.config, null, 2), { mode: 0o600 } ); ``` 4. Check and repair unsafe permissions on pre-existing configuration files. 5. Add `.github-manager.json` to a root `.gitignore` distributed with the project. 6. Prefer fine-grained PATs restricted to selected repositories and required permissions. 7. Separate read-only credentials from credentials used for repository creation, issue changes, and project mutation. 8. Provide token revocation and rotation guidance after suspected disclosure. 9. Avoid copying unrelated webhook and bot credentials into the same plaintext configuration file. ]]>

T08 · Insecure Dependencies

Error
Location
templates/github-actions/deploy-workflow.yml:147
Finding
Mutable Third-Party GitHub Actions Receive API and Webhook Secrets<![CDATA[ ## Vulnerability Details **File Location**: `templates/github-actions/deploy-workflow.yml:147-156`, `templates/github-actions/deploy-workflow.yml:231-240`, `templates/github-actions/deploy-workflow.yml:274-283`, and `templates/github-actions/ci-workflow.yml:129-138` **Vulnerability Type**: CI/CD supply-chain exposure **Risk Level**: High ### Vulnerable Code The deployment template supplies Slack webhook credentials to an action referenced by a mutable major-version tag: ```yaml - name: Notify staging deployment uses: 8398a7/action-slack@v3 with: status: success text: | 🚀 Staging Deployment Complete Version: ${{ needs.prepare.outputs.version }} Commit: ${{ github.sha }} By: ${{ github.actor }} env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_STAGING }} ``` The same pattern is used for production and rollback notifications: ```yaml - name: Notify production deployment uses: 8398a7/action-slack@v3 with: status: success text: | 🎉 PRODUCTION DEPLOYMENT COMPLETE Version: ${{ needs.prepare.outputs.version }} Commit: ${{ github.sha }} Deployed by: ${{ github.actor }} Time: $(date) env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_PRODUCTION }} ``` ```yaml - name: Notify rollback uses: 8398a7/action-slack@v3 with: status: failure text: | 🔄 Rollback Initiated Environment: ${{ needs.prepare.outputs.environment }} Version: ${{ needs.prepare.outputs.version }} Reason: Deployment failed Action: Automatic rollback initiated env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} ``` The CI template similarly supplies credentials to mutable action references: ```yaml - name: Run Snyk security scan uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high - name: Check for secrets uses: gitleaks/gitleaks-action@v2 env: GITLEAKS_LICENSE: ...[truncated 1829 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every third-party action to a reviewed full commit SHA: ```yaml uses: 8398a7/action-slack@<reviewed-40-character-commit-sha> ``` 2. Apply the same SHA-pinning requirement to Snyk, Gitleaks, Docker, release, checkout, setup, and artifact actions. 3. Use Dependabot or Renovate to propose reviewed SHA updates. 4. Declare explicit read-only permissions globally and grant additional rights only to the specific jobs that require them. 5. Isolate secret-bearing notification and scanning steps into minimal jobs. 6. Use protected GitHub environments for production credentials. 7. Rotate webhook and API credentials if an upstream action compromise is suspected. 8. Where practical, replace third-party notification actions with a small, audited script that sends only the required fields to an allowlisted endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate-changelog.js:177
Finding
Arbitrary Writable File Overwrite Through the Changelog Output Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-changelog.js:177-200`, with the output path assigned at `scripts/generate-changelog.js:320-321` **Vulnerability Type**: Path traversal and unsafe file write **Risk Level**: Medium ### Vulnerable Code ```javascript updateChangelogFile(newContent, prepend = true) { const filePath = path.join(process.cwd(), this.options.outputFile); let existingContent = ''; try { if (fs.existsSync(filePath)) { existingContent = fs.readFileSync(filePath, 'utf8'); } } catch (error) { console.error(chalk.red('Error reading existing changelog:'), error.message); } const finalContent = prepend ? newContent + '\n' + existingContent : existingContent + '\n' + newContent; try { fs.writeFileSync(filePath, finalContent); console.log(chalk.green(`✅ Changelog updated: ${filePath}`)); } catch (error) { console.error(chalk.red('Error writing changelog:'), error.message); } } ``` The destination is taken directly from the CLI: ```javascript } else if (arg === '--output' && args[index + 1]) { options.outputFile = args[index + 1]; } ``` ### Technical Analysis `path.join(process.cwd(), userInput)` does not constrain the result to the current working directory. Traversal components such as `../` are normalized and can escape the project directory. Absolute-path behavior and symbolic links can also direct the write to unintended locations. If the destination exists, the script reads it and rewrites it with generated changelog content prepended. If it does not exist, the script creates it. No allowlist, containment check, symlink check, confirmation, or exclusive-write behavior is implemented. ### Attack Path 1. An attacker controls or influences the `--output` argument supplied to the script. 2. The value contains traversal components targeting a file outside the repository. 3. `path.join()` resolves the path without enforcing a project boundary. 4. The ...[truncated 547 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Resolve and validate the destination before reading or writing it: ```javascript const root = fs.realpathSync(process.cwd()); const candidate = path.resolve(root, this.options.outputFile); const relative = path.relative(root, candidate); if ( relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative) ) { throw new Error('Output file must remain inside the project directory'); } ``` Additionally: 1. Restrict output to an approved filename or dedicated output directory. 2. Reject symbolic-link destinations and verify every existing parent component. 3. Avoid following symlinks during the final write where platform APIs permit. 4. Use atomic writes through a safely created temporary file followed by a rename. 5. Require explicit confirmation before overwriting a non-changelog file. 6. Run the generator with minimum filesystem privileges. 7. Add tests for `../`, absolute paths, nested symlinks, and existing-file overwrite cases. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (38)

Credential Access

High
Category
Privilege Escalation
Content
## Requirements

- **Node.js**: >= 14.0.0
- **GitHub**: A [Personal Access Token](https://github.com/settings/tokens) with `repo` scope (recommended)

## Installation
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
## Requirements

- **Node.js**: >= 14.0.0
- **GitHub**: A [Personal Access Token](https://github.com/settings/tokens) with `repo` scope (recommended)

## Installation
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
## Requirements

- **Node.js**: >= 14.0.0
- **GitHub**: A [Personal Access Token](https://github.com/settings/tokens) with `repo` scope (recommended)

## Installation
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Self-Modification

High
Category
Rogue Agent
Content
定期检查更新:
```bash
github self-update
```

查看版本信息:
Confidence
90% confidence
Finding
Documenting a self-update command for the tool creates a supply-chain and self-modification risk if updates are fetched and applied without integrity verification, pinning, or operator review. In an agent skill context, self-updating behavior can change capabilities after trust has been established, potentially introducing malicious code or unsafe behavior later.

Self-Modification

High
Category
Rogue Agent
Content
定期检查更新:
```bash
github self-update
```

查看版本信息:
Confidence
90% confidence
Finding
A documented self-update capability can introduce unreviewed code changes into the toolchain, creating a software supply-chain risk if update sources are compromised or insufficiently verified. In a privileged GitHub management skill, updating itself could alter behavior while retaining access to repositories, deployment workflows, and tokens.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The workflow states that production deployment requires manual approval, but the step only prints informational text and does not enforce any approval gate before continuing to the production deployment step. In a deployment pipeline, this can cause unauthorized or accidental production releases, especially because tag pushes will automatically route to production in this workflow.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This markdown file describes safety-critical actions such as deploying to production and rolling back releases, which can affect system availability and user data. While the document includes token-security notes, it does not warn users in this section about the operational impact or recommend confirmation/review before running these commands.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"environments": {
      "dev": {
        "branch": "develop",
        "autoDeploy": true
      },
      "prod": {
        "branch": "main",
Confidence
85% confidence
Finding
The example configuration enables autoDeploy for the dev environment, which introduces autonomous operational actions that may execute without sufficient human review. In a GitHub management/deployment skill, this increases the chance of unintended code releases, especially if branch protections, tests, or approval gates are weak or misconfigured.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This markdown file describes safety-critical operations such as deploying to production and rolling back releases, which can directly affect system integrity and availability. Although the document has general security notes, this section does not warn users about operational risk, required approvals, or potential service impact before running these commands.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"environments": {
      "development": {
        "branch": "develop",
        "autoDeploy": true,
        "notifyOnFailure": true,
        "requiredChecks": ["test", "lint"]
      },
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"environments": {
      "development": {
        "branch": "develop",
        "autoDeploy": true,
        "notifyOnFailure": true,
        "requiredChecks": ["test", "lint"]
      },
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"environments": {
      "development": {
        "branch": "develop",
        "autoDeploy": true,
        "notifyOnFailure": true,
        "requiredChecks": ["test", "lint"]
      },
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"environments": {
      "development": {
        "branch": "develop",
        "autoDeploy": true,
        "notifyOnFailure": true,
        "requiredChecks": ["test", "lint"]
      },
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The CLI accepts a GitHub token on the command line and persists it in plaintext to `.github-manager.json` under the current working directory. Command-line secrets can be exposed through shell history, process listings, logs, or CI traces, and the local config file may be accidentally committed or read by other local users/processes.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
{
  "name": "github-manager-cli",
  "version": "1.0.0",
  "description": "A comprehensive GitHub repository management tool with code review, auto-deployment, changelog generation, CI/CD configuration, bug tracking, and project management automation",
  "main": "github-cli.js",
  "bin": {
    "github": "./github-cli.js"
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file's comments, CLI output, and date formatting are fixed to Chinese, including an explicit zh-CN locale at runtime. This forces a specific language/locale experience without any opt-in, selection mechanism, or documented regional limitation.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This code reads GitHub authentication data, including a token, from .github-manager.json and immediately uses it to authenticate API calls. Although the tool's purpose is code review, there is no nearby disclosure, prompt, or warning to the user in this file that sensitive credentials are being accessed from local storage.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script builds a shell command string for `git log` and appends `sinceTag` directly before passing it to `execSync`. Because `sinceTag` can come from the `--since` CLI argument, an attacker can inject shell metacharacters and execute arbitrary commands in the user's environment when the script runs.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file header, operational messages, and CLI usage are written in Chinese, which effectively forces a specific language for users. The policy allows fixed locale behavior only when user choice or a justified regional constraint is provided, neither of which appears here.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The release body asserts that security scans passed even though the workflow contains no security scanning step. This creates false security attestations that can mislead operators, auditors, or downstream users into trusting artifacts that were never scanned.

Missing User Warnings

Low
Confidence
79% confidence
Finding
This markdown file documents actions that can modify repository state, including closing issues and creating CI/CD workflow files, but it does not explicitly warn users about reviewing targets or confirming changes before execution. For markdown files, user-facing warnings are expected when behaviors could affect user data or system integrity.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language instructions and examples are presented only in Chinese, which effectively forces a specific language for users. The file does not mention that the skill is intended only for Chinese-speaking users or provide any language/locale opt-in.

Missing User Warnings

Low
Confidence
76% confidence
Finding
The skill documentation includes commands to create repositories and later to create, assign, and close issues, all of which change remote GitHub resources. The description does not clearly warn that these actions will modify live repository/project data, which is relevant user-impact information for a markdown skill description.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The GitHub client is initialized with a fixed time zone, which imposes a locale setting on all users of the tool. The file does not provide opt-in, configuration, or justification that this is intended only for a China-specific environment.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "GitHub Manager Team",
  "license": "MIT",
  "dependencies": {
    "@octokit/rest": "^20.0.2",
    "commander": "^11.0.0",
    "chalk": "^4.1.2",
    "inquirer": "^8.2.6",
Confidence
86% confidence
Finding
Using a caret range for @octokit/rest allows future compatible releases to be installed automatically, which can introduce supply-chain risk or unexpected vulnerable versions over time. In a GitHub management CLI that likely handles repository administration and API tokens, dependency drift is more sensitive than in a simple local utility.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.dynamic_code_execution

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/generate-changelog.js:35

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/code-review.js:257