Back to skill

Security audit

weekly-gitlog

Security checks for vulnerabilities and agentic risk

Overview

This skill is a small, disclosed git changelog helper that reads commit history and does not show hidden writes, network access, persistence, or credential use.

Installers should treat this as a benign utility, but avoid running it on untrusted repositories in a sensitive terminal or feeding its JSON output directly into automation that assumes all commit metadata is safe and complete.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/weekly-gitlog.mjs:58
Finding

Terminal Control-Sequence Injection Through Untrusted Git Metadata

Content
View full analysis

Vulnerability Details

File Location: scripts/weekly-gitlog.mjs, lines 58-84
Vulnerability Type: Unsanitized terminal output
Risk Level: Medium

Vulnerable Code

js
// group: author -> day -> [ {hash, subject} ]
const authors = new Map();
for (const line of raw.split("\n")) {
  if (!line) continue;
  const [author, day, hash, subject] = line.split("\x1f");
  if (!authors.has(author)) authors.set(author, new Map());
  const days = authors.get(author);
  if (!days.has(day)) days.set(day, []);
  days.get(day).push({ hash, subject });
}

if (opts.json) {
  const out = {};
  for (const [author, days] of authors) {
    out[author] = Object.fromEntries(days);
  }
  console.log(JSON.stringify(out, null, 2));
  return;
}

const authorNames = [...authors.keys()].sort();
for (const author of authorNames) {
  console.log(`## ${author}`);
  const days = authors.get(author);
  for (const day of [...days.keys()].sort().reverse()) {
    console.log(`### ${day}`);
    for (const { hash, subject } of days.get(day)) {
      console.log(`  ${hash} ${subject}`);
    }
  }
  console.log("");
}

Technical Analysis

The author email and commit subject originate from repository-controlled Git commit metadata. The script writes those values directly to the terminal without escaping ANSI escape sequences or other control characters.

An attacker who can place commits in a repository can embed terminal control sequences in an author field or commit subject. When a user runs the Skill in text mode, the terminal interprets those sequences rather than displaying them literally. Depending on terminal capabilities and configuration, this can clear or rewrite visible output, alter colors, create misleading hyperlinks, change the terminal title, or attempt terminal-specific operations such as clipboard manipulation.

The use of execFileSync with an argument array prevents shell-command ...[truncated 1218 chars]

Remediation
View remediation

Remediation Suggestions

Treat every Git metadata field as untrusted before terminal rendering.

  1. Remove or visibly escape C0, DEL, C1, ANSI CSI, and OSC control sequences from author and subject values.
  2. Preserve ordinary Unicode text while replacing unsafe controls with escaped representations such as \x1b.
  3. Validate that every parsed record contains the expected four fields before storing or rendering it.
  4. Consider a dedicated safe-text function for all text-mode output:
js
function safeTerminalText(value) {
  return String(value)
    .replace(/\x1B(?:[@-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g, "")
    .replace(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/g, "");
}

console.log(`## ${safeTerminalText(author)}`);
console.log(`  ${safeTerminalText(hash)} ${safeTerminalText(subject)}`);
  1. Add regression tests using commit metadata containing escape characters, newlines, field delimiters, and OSC sequences.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/weekly-gitlog.mjs:67
Finding

Prototype Setter Abuse in JSON Output Through Crafted Author Identity

Content
View full analysis

Vulnerability Details

File Location: scripts/weekly-gitlog.mjs, lines 67-72
Vulnerability Type: Unsafe attacker-controlled object property assignment
Risk Level: Low

Vulnerable Code

js
if (opts.json) {
  const out = {};
  for (const [author, days] of authors) {
    out[author] = Object.fromEntries(days);
  }
  console.log(JSON.stringify(out, null, 2));
  return;
}

The author key used above originates from Git metadata:

js
const [author, day, hash, subject] = line.split("\x1f");
if (!authors.has(author)) authors.set(author, new Map());

Technical Analysis

The JSON output accumulator is an ordinary object with Object.prototype in its prototype chain. Assigning an attacker-controlled property named __proto__ to such an object invokes the legacy prototype setter instead of creating a normal own property.

A crafted Git author email equal to __proto__ can therefore change the prototype of out. In this implementation, the assigned value is the object returned by Object.fromEntries(days). The affected author entry may then be omitted from JSON.stringify, because inherited properties are not serialized as own properties.

This is a localized form of prototype manipulation. The current script does not subsequently merge this object into privileged application state, so the reviewed code does not establish application-wide prototype pollution or code execution. Nevertheless, attacker-controlled Git metadata can corrupt the machine-readable output.

Attack Path

  1. An attacker creates a Git commit whose author email is __proto__.
  2. The victim runs the script with the --json option against the crafted repository.
  3. The author value is accepted as a key in the authors map.
  4. The assignment out[author] = Object.fromEntries(days) resolves to out["__proto__"] = ....
  5. JavaScript invokes the inherited __proto__ setter and changes the prototype o ...[truncated 640 chars]
Remediation
View remediation

Remediation Suggestions

Avoid assigning untrusted keys to objects that inherit from Object.prototype.

  1. Create the output container with a null prototype:
js
const out = Object.create(null);
for (const [author, days] of authors) {
  out[author] = Object.fromEntries(days);
}
  1. Alternatively, construct the object in one operation while explicitly defining own data properties:
js
const out = Object.fromEntries(
  [...authors].map(([author, days]) => [
    author,
    Object.fromEntries(days),
  ])
);
  1. If downstream consumers do not require arbitrary author strings as object keys, use an array-based schema instead:
js
const out = [...authors].map(([author, days]) => ({
  author,
  days: Object.fromEntries(days),
}));
  1. Add tests for special keys including __proto__, constructor, and prototype, and verify that each author appears as an own serialized entry.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (3)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 31)May include surrounding context.

md
node scripts/weekly-gitlog.mjs

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 34)May include surrounding context.

md
node scripts/weekly-gitlog.mjs

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

md
node scripts/weekly-gitlog.mjs

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/weekly-gitlog.mjs:44