Back to skill

Security audit

feynman-fsrs-pro

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent study-tutor purpose, but it stores study data persistently and includes unsafe database and command-execution practices that users should review before installing.

Install only if you are comfortable granting the skill access to a local Obsidian vault and a PostgreSQL memory database. Before using it, replace hardcoded database credentials with protected configuration, rotate the exposed password, avoid running the provided schema.sql on an existing database without a backup, and fix the Obsidian CLI calls to use argument-array execution instead of shell strings.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/database.js:18
Finding

Shell Command Injection Through Obsidian Note Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/database.js:18-24 and scripts/database.js:119-137
Vulnerability Type: OS command injection through shell interpolation
Risk Level: High

Vulnerable Code

js
function obsidianCmd(args) {
  const cmd = `obsidian ${args}`.trim();
  try {
    return execSync(cmd, { encoding: "utf-8", shell: true });
  } catch (err) {
    return ""; // Command failures return an empty string
  }
}
js
export async function get_note_content(conceptName) {
  const filePath = findNotePath(conceptName);
  if (!filePath) {
    return `❌ Note file not found: ${conceptName}\nPlease confirm that the note exists in vault "${OBSIDIAN_VAULT}".`;
  }

  // path= uses an exact path, while file= uses name resolution
  const content = obsidianCmd(`read vault=${OBSIDIAN_VAULT} path="${filePath}"`);
  if (!content.trim()) {
    return `❌ Failed to read: ${conceptName}`;
  }
  return content;
}

Technical Analysis

obsidianCmd() constructs a single command string and passes it to execSync() with shell: true. The filePath value originates from filenames returned by the Obsidian CLI and is interpolated directly into this shell command.

Wrapping the path in double quotes does not make it safe. Shell constructs such as command substitution with $(...) or backticks remain active inside double quotes. A filename containing an escaped quote may also terminate the quoted argument and introduce shell metacharacters.

The broad exception handler further obscures exploitation because command failures and malicious side effects are reduced to an empty output rather than being logged or surfaced.

Attack Path

  1. An attacker creates or synchronizes a Markdown note with a shell-active payload in its filename or relative path.
  2. listVaultFiles() obtains the attacker-controlled path from the Obsidian vault.
  3. The path is selected by `findNoteP ...[truncated 1124 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace shell-string execution with execFileSync() or spawnSync() and pass every argument as a separate array element.
  • Explicitly disable shell processing.
  • Validate vault names and paths against expected character and path rules.
  • Reject control characters, null bytes, and unexpected absolute paths.
  • Preserve and report command errors instead of silently returning an empty string.
  • Run the Skill under a dedicated, least-privileged operating-system account.

A safer implementation would follow this pattern:

js
import { execFileSync } from "child_process";

function obsidianCmd(args) {
  return execFileSync("obsidian", args, {
    encoding: "utf-8",
    shell: false,
  });
}

const content = obsidianCmd([
  "read",
  `vault=${OBSIDIAN_VAULT}`,
  `path=${filePath}`,
]);

Argument-array execution is the primary control; custom shell escaping should not be used as a substitute.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/database.js:6
Finding

Hardcoded Plaintext PostgreSQL Credentials

Content
View full analysis

Vulnerability Details

File Location: scripts/database.js:6-12 and SKILL.md:20-26
Vulnerability Type: Hardcoded secret and weak plaintext credential
Risk Level: Medium

Vulnerable Code

js
const pool = new Pool({
  user: "openclaw_feiman",
  host: "127.0.0.1",
  database: "openclaw_feiman",
  password: "12345678",
  port: 5432,
});

The same connection parameters, including the plaintext password, are also disclosed in SKILL.md:

text
Database connection parameters:
- Username: openclaw_feiman
- Host: 127.0.0.1
- Database: openclaw_feiman
- Password: 12345678
- Port: 5432

Technical Analysis

A static PostgreSQL username and weak password are embedded in both executable source code and public Skill documentation. Any party able to inspect the installed or distributed package can recover the credential.

Secrets committed to source cannot be rotated independently of the package and may be copied into archives, registries, logs, caches, or forks. The simple numeric password also has low entropy and is unsuitable for protecting a database account.

The configured host is localhost, which limits direct remote use in the current configuration, but it does not protect against other local users, compromised processes, containers sharing the host network, or deployments that later expose PostgreSQL.

Attack Path

  1. An attacker obtains read access to the Skill package, registry artifact, installation directory, or documentation.
  2. The attacker extracts the PostgreSQL username, database name, port, and password.
  3. From a process that can reach 127.0.0.1:5432, the attacker authenticates as openclaw_feiman.
  4. The attacker exercises whatever permissions have been assigned to that database role.
  5. If the credential has been reused elsewhere, the attacker may attempt access to those additional services.

Impact Assessment

The precise impact depends on ...[truncated 637 chars]

Remediation
View remediation

Remediation Suggestions

  • Immediately rotate the exposed password and use a strong, unique secret.
  • Remove credentials from database.js, SKILL.md, repository history, published artifacts, and examples.
  • Load connection settings from protected environment variables or a platform secret manager.
  • Configure separate database roles for runtime use and schema migration.
  • Grant the runtime role only the necessary SELECT, INSERT, and UPDATE permissions on the required table and sequence.
  • Do not grant the runtime account table-drop, role-management, database-creation, or superuser permissions.
  • Restrict PostgreSQL with host-based authentication rules, local firewall controls, and narrowly scoped listen addresses.
  • Where supported by the deployment, require TLS and verify the server certificate.
  • Add secret scanning to development and publication workflows.

Example configuration:

js
const pool = new Pool({
  user: process.env.FEYNMAN_DB_USER,
  host: process.env.FEYNMAN_DB_HOST ?? "127.0.0.1",
  database: process.env.FEYNMAN_DB_NAME,
  password: process.env.FEYNMAN_DB_PASSWORD,
  port: Number(process.env.FEYNMAN_DB_PORT ?? 5432),
});

The environment variables must be supplied through a protected secret facility rather than committed to another tracked file.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/schema.sql:11
Finding

Destructive Database Initialization Without Safeguards

Content
View full analysis

Vulnerability Details

File Location: scripts/schema.sql:11
Vulnerability Type: Unsafe destructive database initialization
Risk Level: Medium

Vulnerable Code

sql
-- Create the feynman_memory table
DROP TABLE IF EXISTS feynman_memory CASCADE;

CREATE TABLE feynman_memory (
    id SERIAL PRIMARY KEY,
    concept_name VARCHAR(255) NOT NULL UNIQUE,
    obsidian_path TEXT,
    stability REAL DEFAULT 0.0,
    difficulty REAL DEFAULT 5.0,
    last_review TIMESTAMP WITH TIME ZONE,
    next_review TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    weak_points JSONB DEFAULT '[]'::jsonb,
    review_history JSONB DEFAULT '[]'::jsonb,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Technical Analysis

The documented initialization script unconditionally drops the existing feynman_memory table before recreating it. The CASCADE modifier also removes database objects that depend on the table.

The script provides no confirmation prompt, backup procedure, explicit reset flag, environment check, or migration guard. It is presented as an initialization command, so a user may reasonably run it against an existing installation without realizing that it functions as a destructive reset.

This is primarily an availability and integrity flaw rather than an external code-execution issue.

Attack Path

  1. A user or automated deployment follows the documented command to initialize or repair the database.
  2. The script connects to a database that already contains learning records.
  3. DROP TABLE IF EXISTS feynman_memory CASCADE deletes the table and all stored review data.
  4. PostgreSQL also removes dependent objects because of CASCADE.
  5. The subsequent CREATE TABLE statement creates an empty replacement, making the operation appear successful despite the data loss.

An attacker with the ...[truncated 673 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace destructive initialization with versioned, idempotent migrations.
  • Use CREATE TABLE IF NOT EXISTS for first-time setup.
  • Remove CASCADE from routine installation and upgrade scripts.
  • Place destructive reset behavior in a separate, explicitly named script such as reset-database.sql.
  • Require an explicit operator confirmation or deployment flag before destructive operations.
  • Verify the target database name and environment before executing any reset.
  • Create and validate a backup before dropping application data.
  • Run schema migrations in transactions when PostgreSQL permits the relevant operations.
  • Use a dedicated migration role; the normal runtime role should not have DROP privileges.

A non-destructive first-install pattern begins with:

sql
CREATE TABLE IF NOT EXISTS feynman_memory (
    id SERIAL PRIMARY KEY,
    concept_name VARCHAR(255) NOT NULL UNIQUE,
    obsidian_path TEXT,
    stability REAL DEFAULT 0.0,
    difficulty REAL DEFAULT 5.0,
    last_review TIMESTAMP WITH TIME ZONE,
    next_review TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    weak_points JSONB DEFAULT '[]'::jsonb,
    review_history JSONB DEFAULT '[]'::jsonb,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill’s declared purpose is a guided tutoring workflow, but the content also embeds operational instructions for direct database access and Obsidian CLI usage without clearly surfacing those side effects in the skill description. This mismatch is dangerous because users and operators may grant trust or permissions based on the declared educational purpose while the skill can read notes and update persistent storage.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Plaintext database credentials are embedded without any warning or secure-handling guidance. This materially increases the chance of credential leakage, unauthorized reuse, and downstream compromise of stored notes metadata and review history.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs persistent storage of weak points, feedback, and detailed review history derived from user responses. This is dangerous because those free-form entries may contain sensitive personal, educational, or proprietary information, creating long-term retention and leakage risk if the database is accessed improperly.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The workflow mandates logging each user answer and conversation-derived summaries after every session, which expands the amount of sensitive natural-language content retained in the database. If compromised, these logs can reveal learning weaknesses, personal notes context, and potentially confidential material discussed during tutoring.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description is written as a Chinese-only interaction contract and does not indicate that users may choose another language or that the locale restriction is required for a region-specific purpose. This is a natural-language policy issue because it imposes a specific language without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill description does not warn users that it accesses local notes and writes to a database during normal operation. This creates a consent and trust problem because users may provide sensitive study material without understanding that persistent storage and file access are involved.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file exposes hard-coded PostgreSQL credentials in plaintext. Anyone with access to the skill source can reuse these credentials to connect to the database, read stored study records, or tamper with review data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code accepts an arbitrary file path and imports note content from disk, which is a safety-relevant file access operation. Although the file has a general docstring, there is no command-specific warning, confirmation, or user-facing notice that the tool will read local files from the supplied path.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The module imports child_process and builds shell commands with string interpolation in obsidianCmd(), then passes user-influenced data such as file paths into execSync with shell:true. In a tutoring skill, this creates an unnecessary command-execution boundary where malicious note names or paths returned by the CLI could trigger shell injection or unintended local command execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The PostgreSQL username and password are hardcoded in source code, exposing reusable credentials to anyone who can read the skill files. If the code is shared, logged, or deployed insecurely, an attacker could connect to the local database and read or modify the learner's memory data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The obsidianCmd function executes shell commands via execSync with shell=true, which is a safety-relevant operation. Although there is an internal docstring, there is no visible confirmation prompt or user-facing disclosure that the skill invokes external CLI commands against the local system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script unconditionally executes DROP TABLE IF EXISTS feynman_memory CASCADE, which can destroy existing data and dependent objects without any confirmation, backup step, or prominent warning. In this skill context, the database is a memory store for spaced-repetition learning, so accidental execution could wipe a user's review history and linked workflow state, causing integrity and availability loss.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

Natural-language strings in the header and runtime errors are Chinese-only, and the file does not indicate that language is configurable or intentionally limited to a Chinese-speaking context. This creates a language-policy concern because the skill effectively forces one locale without user opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The header comment presents the CLI usage examples as the supported commands, but it does not include import-note. The switch statement later implements import-note, which performs note import side effects, so the documentation understates actual behavior rather than merely leaving out an internal detail.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file contains natural-language comments and user-visible return strings in Chinese, indicating the skill is designed around a specific language without offering a language choice. This can violate language/locale policy when no opt-in or documented locale constraint is provided.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The documentation states that the function executes the CLI command and returns stdout, which implies callers receive command output or an error. In practice, the function catches all failures and silently returns an empty string, causing documented behavior and actual behavior to diverge in a way that can hide sync/read failures.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The returned error messages are hardcoded in Chinese and will be shown directly to users. The file does not provide any opt-in, fallback, or documented justification for enforcing a specific language.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description is written only in Chinese ("基于 FSRS 算法的费曼学习记忆系统"), which can be interpreted as imposing a specific language/locale in user-facing metadata. The file does not offer an alternate language or indicate that the skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

Using a caret range for the pg dependency allows newer minor/patch releases to be installed without explicit review, reducing build reproducibility and increasing supply-chain risk. In a skill that interacts with PostgreSQL memory storage, dependency drift could introduce vulnerable or malicious code into a component that processes potentially sensitive study data and database connections.

Content

Scanner excerpt · scripts/package.json (reported line 21)May include surrounding context.

json
"author": "",
  "license": "MIT",
  "dependencies": {
    "pg": "^8.11.3"
  },
  "engines": {
    "node": ">=18.0.0"

Unverifiable Dependency: pg has 1 known advisory(ies) (CVE-2017-16082 (Remote Code Execution in pg)), 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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file’s comments and echoed completion messages are written entirely in Chinese, which imposes a specific language on operators of the skill. There is no indication that the skill is region-specific or that users can choose another language, so this may violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/database.js:25