Back to skill

Security audit

Diy Pc Ingest

Security checks for vulnerabilities and agentic risk

Overview

The skill’s Notion ingestion purpose is clear, but it includes live page update and archive powers that can affect more Notion content than the configured DIY-PC tables if misused.

Review before installing. Use a Notion integration shared only with the four intended DIY-PC databases, inspect the generated JSONL before execution, and avoid page_id/id, archive, and overwrite unless you intentionally want to modify a specific page. Treat runs as live writes to Notion, not a dry run.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/notion_apply_records.js:455
Finding

Unrestricted Direct Modification or Archival of Accessible Notion Pages

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notion_apply_records.js:309
Finding

Ambiguous Upsert Matches Are Treated as Missing Records and Create Duplicates

Content
View full analysis
= 2 && keyProps.every(k => propsIn?.[k])) { const first = keyProps[0]; const firstSchema = schProps[first] || {}; const firstType = firstSchema.type; const firstVal = normalize(propsIn[first]); let hits = []; if (firstType === 'title') hits = await queryByTitle(cfg, ds, first, firstVal, 25); else if (firstType === 'rich_text') hits = await queryByRichText(cfg, ds, first, firstVal, 25); const narrowed = hits.filter(row => { for (const k of keyProps) { const wantRaw = propsIn[k]; if (wantRaw === null || wantRaw === undefined || wantRaw === '') return false; const got = getValueFromRow(row, k); const want = typeof wantRaw === 'string' ? normalize(wantRaw) : String(wantRaw); const gotN = typeof got === 'string' ? normalize(got) : (got === null || got === undefined ? null : String(got)); if (gotN !== want) return false; } return true; }); if (narrowed.length === 1) return narrowed[0]; return null; } ``` The caller interprets that ambiguous `null` result as permission to create a new page: ```javascript const existing = await findExisting(cfg, ids, target, schema, propsIn); if (existing) { const patch = buildPatch(schema, propsIn, existing.properties || {}, overwrite); if (Object.keys(patch).length) { const updated = await notionReq(cfg, 'PATCH', `/pages/${existing.id}`, { properties: patch }); summary.updated += 1; results.push({ action: 'updated', target, id: updated.id, url ...[truncated 2041 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill presents itself as an ingestion/classification workflow, but the documented input to the apply script is already-formed JSONL records and it also supports undeclared record-archive and cross-table mirroring behavior. This mismatch is risky because operators may trust the skill as a benign formatter while it can perform broader state-changing actions in Notion than the description implies.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill presents itself as an ingestion/classification workflow, but the documented input to the apply script is already-formed JSONL records and it also supports undeclared record-archive and cross-table mirroring behavior. This mismatch is risky because operators may trust the skill as a benign formatter while it can perform broader state-changing actions in Notion than the description implies.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill presents itself as an ingestion/classification workflow, but the documented input to the apply script is already-formed JSONL records and it also supports undeclared record-archive and cross-table mirroring behavior. This mismatch is risky because operators may trust the skill as a benign formatter while it can perform broader state-changing actions in Notion than the description implies.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
5) **Upsert into Notion** using `scripts/notion_apply_records.js`:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
5) **Upsert into Notion** using `scripts/notion_apply_records.js`:

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 166)May include surrounding context.

  • 配置先: ~/.config/diy-pc-ingest/config.json
bash
mkdir -p ~/.config/diy-pc-ingest
cp references/config.example.json ~/.config/diy-pc-ingest/config.json

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly documents operations that can overwrite existing Notion records, null out fields, directly PATCH arbitrary pages, and archive pages, but it does not require a confirmation step or warn that these actions can modify or hide existing data. In a skill whose purpose is to ingest messy user-provided text and perform upserts, this increases the risk of accidental destructive changes from misclassification or malformed input.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly relies on environment variables, local file reads, and network access to retrieve a Notion API key, load local configuration, and write to Notion, yet it declares no tool scope or permission boundary. This creates an authorization-transparency gap: a user or platform cannot easily tell that the skill can access local secrets and modify remote data, increasing the chance of unintended secret exposure or unauthorized writes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The workflow instructs the agent to upsert records into external Notion tables and report created links, but it does not require an explicit warning or confirmation that external data will be modified. In an agent setting, silent writes to a live workspace can lead to accidental data corruption, duplicate records, or modifications based on misparsed input.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Direct page-by-ID update and archive operations are high-risk mutation capabilities, and documenting them without a strong safety warning or confirmation step makes accidental or malicious destructive changes easier. Because these controls bypass ordinary upsert matching, a malformed or attacker-influenced record can target arbitrary pages for overwrite or archival if the integration has access.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/_deprecated/notion_apply_records.py (reported line 17)May include surrounding context.

python
Notion API:
- Query/schema via data_sources
- Create rows via pages with parent.database_id
"""

from __future__ import annotations

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code issues authenticated HTTP requests to the Notion API and later uses them to create and patch pages, which can modify remote user data. While the module docstring describes purpose, there is no runtime confirmation, visible user disclosure, or explicit warning in this file about making live changes to Notion content.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script accepts page_id/id and archive/archived fields and will directly PATCH or archive any supplied Notion page, which exceeds the advertised upsert-only behavior. In an agent skill that ingests user-pasted text, this creates a dangerous capability expansion: if upstream parsing or prompt injection introduces those fields, the script can modify or archive arbitrary reachable pages rather than only rows identified through safe matching logic.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The direct PATCH/archive path can make destructive remote changes without any in-script confirmation, preview, or safeguard. Because archiving is more destructive than ordinary upserts and can be triggered by input fields, accidental or adversarial records could hide or alter data irreversibly in the user's Notion workspace.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/bootstrap_config.js (reported line 5)May include surrounding context.

js
/**
 * bootstrap_config.js
 *
 * Create ~/.config/diy-pc-ingest/config.json by discovering Notion IDs via /v1/search.
 * Requires NOTION_API_KEY (or NOTION_TOKEN) and that the target data sources are shared with the integration.
 *
 * Usage:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/_deprecated/notion_apply_records.py (reported line 29)May include surrounding context.

python
import os from 'os';
import path from 'path';

const API = 'https://api.notion.com/v1';
const NOTION_VERSION = process.env.NOTION_VERSION || '2025-09-03';

function die(msg, code = 1) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/bootstrap_config.js (reported line 18)May include surrounding context.

js
import os from 'os';
import path from 'path';

const API = 'https://api.notion.com/v1';
const NOTION_VERSION = process.env.NOTION_VERSION || '2025-09-03';

function die(msg, code = 1) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/notion_apply_records.js (reported line 20)May include surrounding context.

js
import os from 'os';
import path from 'path';

const API = 'https://api.notion.com/v1';
const NOTION_VERSION = process.env.NOTION_VERSION || '2025-09-03';

function die(msg, code = 1) {

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README instructs users to create schema fields exactly as specified and explicitly says to use Japanese property names as-is. This imposes a specific language/locale requirement without opt-in or an alternative localized schema, which matches the policy concern for forced language selection.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The example config includes hard-coded Japanese field names such as "名前", "型番", "シリアル", and "取り外し表示名" alongside English keys. Because this is a manifest/config file and no surrounding text explains that Japanese locale is optional or required for a region-specific integration, it can be interpreted as imposing a language-specific schema without user choice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module documentation states a narrow record format, but the implementation also honors undocumented control fields for direct page updates and archiving. This documentation/behavior mismatch is security-relevant because callers, reviewers, or higher-level agents may assume the tool only performs constrained upserts while hidden fields enable broader mutations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

A storage record can trigger an additional write to the pcconfig table via mirror_to_pcconfig, so one requested operation may silently produce two remote mutations. This violates least surprise and broadens the blast radius of malformed or adversarial input, especially in an AI-driven ingestion flow where hidden flags may be injected without the user's awareness.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/bootstrap_config.js:19

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/notion_apply_records.js:84