Skip to content

Commit 9806a94

Browse files
yunbowclaude
andcommitted
feat(guidelines): パストラバーサル防止・AI/LLMセキュリティ・MCPサーバーガイドラインを追加
- common/security.md: Section 3.12 にパストラバーサル防止パターンを追加 - common/security.md: Section 13 として AI/LLM セキュリティを新設 (間接プロンプトインジェクション・ツールポイズニング・秘密情報露出・依存パッケージ固定) - frameworks/nodejs-cli/mcp-server.md: MCP サーバー固有ガイドラインを新規作成 (transport制約・ツール設計・2層レスポンス・マルチターンパターン・テスト戦略) - frameworks/nodejs-cli/README.md: mcp-server.md エントリを追加 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e334f31 commit 9806a94

3 files changed

Lines changed: 619 additions & 0 deletions

File tree

03_guidelines/common/security.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,41 @@ export function isAdminIpAllowed(clientIp: string | null): boolean
383383

384384
---
385385

386+
## 3.12 Path Traversal Prevention
387+
388+
When a tool or API endpoint accepts file paths as input (`source_path`, `output_path`, `file_name`, etc.), prevent access outside the allowed base directory:
389+
390+
```typescript
391+
import path from "path";
392+
393+
/**
394+
* Resolve and validate that the given path stays within the allowed base directory.
395+
* Throws if a path traversal is detected.
396+
*/
397+
function validatePath(inputPath: string, allowedBase: string): string {
398+
const resolved = path.resolve(inputPath);
399+
const base = path.resolve(allowedBase);
400+
401+
if (!resolved.startsWith(base + path.sep) && resolved !== base) {
402+
throw new Error(`Path traversal detected: ${inputPath}`);
403+
}
404+
return resolved;
405+
}
406+
```
407+
408+
```typescript
409+
// ❌ BAD: directly using user-supplied path
410+
const content = await fs.readFile(userSuppliedPath, "utf8");
411+
412+
// ✅ GOOD: validate before use
413+
const safePath = validatePath(userSuppliedPath, process.env.DATA_DIR!);
414+
const content = await fs.readFile(safePath, "utf8");
415+
```
416+
417+
**Apply to:** any endpoint or CLI flag that receives a file path (`--output`, `source_path`, `import_file`, etc.). Even in local CLI tools, path traversal can expose unintended files when inputs come from external sources (MCP tool args, config files, user prompts).
418+
419+
---
420+
386421
## 3.11 Maintenance Mode
387422

388423
```typescript
@@ -530,6 +565,99 @@ if (
530565

531566
---
532567

568+
---
569+
570+
## 13. AI / LLM Integration Security
571+
572+
As applications increasingly integrate LLM capabilities (AI APIs, MCP servers, agent workflows), new attack surfaces emerge that traditional web security does not cover. Reference: **[OWASP LLM Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/)** / **[OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/)**.
573+
574+
---
575+
576+
### 13.1 Indirect Prompt Injection (XPIA)
577+
578+
External content retrieved by the application (web pages, documents, API responses, database records) may contain hidden instructions that the LLM interprets as legitimate commands.
579+
580+
```typescript
581+
// ❌ BAD: passing raw external content directly into a prompt
582+
const pageContent = await fetchWebPage(url);
583+
const prompt = `Summarize this page: ${pageContent}`;
584+
585+
// ✅ GOOD: sanitize external content before injecting into prompts
586+
function sanitizeExternalContent(text: string, maxLength = 50_000): string {
587+
return text
588+
// Strip tags commonly used for instruction smuggling
589+
.replace(/<\/?(?:IMPORTANT|SYSTEM|INST|s|script)[^>]*>/gi, "")
590+
.replace(/<!--[\s\S]*?-->/g, "")
591+
// Strip zero-width and invisible unicode characters
592+
.replace(/[\u200B-\u200D\uFEFF\u00AD]/g, "")
593+
.slice(0, maxLength);
594+
}
595+
596+
const safeContent = sanitizeExternalContent(await fetchWebPage(url));
597+
const prompt = `Summarize this page: ${safeContent}`;
598+
```
599+
600+
**Rule:** Treat all externally-sourced content as untrusted datanever as trusted instructions.
601+
602+
---
603+
604+
### 13.2 Tool / Plugin Poisoning
605+
606+
When an AI agent can invoke tools whose definitions (name, description, schema) are loaded from external or third-party sources, those definitions can be weaponized to exfiltrate data or perform unauthorized actions.
607+
608+
```typescript
609+
// ✅ Verify tool definitions before registration
610+
function verifyToolDefinition(tool: ToolDefinition, expectedHash: string): void {
611+
const actualHash = sha256(JSON.stringify(tool));
612+
if (actualHash !== expectedHash) {
613+
throw new Error(`Tool definition hash mismatch for "${tool.name}". Possible tampering.`);
614+
}
615+
}
616+
```
617+
618+
**Mitigations:**
619+
- Pin external MCP server / plugin versions and verify via hash/checksum
620+
- Validate that tool `description` fields do not contain instruction-like patterns (`"always"`, `"ignore previous"`, `"secretly"`, etc.)
621+
- Never grant AI tools more permissions than required (principle of least privilege, Section 1)
622+
- Log all tool invocations with parameters; alert on unexpected file access or external network calls
623+
624+
---
625+
626+
### 13.3 Secret Exposure via LLM
627+
628+
LLMs may inadvertently reproduce secrets present in their context (system prompts, tool responses, retrieved documents).
629+
630+
```typescript
631+
// ✅ Redact secrets from all content before passing to LLM
632+
const REDACT_PATTERNS = [
633+
/\b(sk-[A-Za-z0-9]{32,})/g, // API keys
634+
/\b(Bearer\s+[A-Za-z0-9\-._~+/]+=*)/g, // Bearer tokens
635+
/([A-Za-z0-9+/]{40,}={0,2})/g, // Base64-encoded secrets (heuristic)
636+
];
637+
638+
function redactSecrets(text: string): string {
639+
return REDACT_PATTERNS.reduce(
640+
(t, pattern) => t.replace(pattern, "[REDACTED]"),
641+
text
642+
);
643+
}
644+
```
645+
646+
- Never include API keys, DB credentials, or PII in prompts, system messages, or tool response content
647+
- Apply the same redact rules as server-side logging (Section 9 / common/logging.md PII Redaction)
648+
649+
---
650+
651+
### 13.4 Dependency Pinning for AI Packages
652+
653+
AI / MCP related packages (e.g., `@modelcontextprotocol/sdk`, `mcp-remote`, AI SDK wrappers) have a history of rapidly-introduced CVEs.
654+
655+
- Pin exact versions in `package.json` for all AI-related packages
656+
- Run `npm audit` / Dependabot on every PR (same SLA as Section 10)
657+
- For `mcp-remote` specifically: CVE-2025-6514 (RCE via unsanitized OAuth metadata) — upgrade to the patched version immediately if used
658+
659+
---
660+
533661
## Summary
534662

535663
* Authentication and authorization based on **Zero Trust principles**
@@ -540,3 +668,5 @@ if (
540668
* Respond to CI/CD vulnerabilities promptly based on SLAs
541669
* Ensure attack detection and response through logging, monitoring, and alerting
542670
* Comply with privacy laws and minimize user data collection
671+
* **Validate file paths** against an allowed base directory to prevent path traversal (Section 3.12)
672+
* **Sanitize all external content** before injecting into LLM prompts; treat it as untrusted data (Section 13)

03_guidelines/frameworks/nodejs-cli/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ See [overview.md](./overview.md) for the full technology stack and replaceable l
1313
| [pipeline.md](./pipeline.md) | Pipeline Orchestration & Step Management ||
1414
| [config.md](./config.md) | Configuration Resolution & Defaults | cosmiconfig, c12 |
1515
| [process-lifecycle.md](./process-lifecycle.md) | Exit Codes, Signals & I/O ||
16+
| [mcp-server.md](./mcp-server.md) | MCP Server: Transport Constraints, Tool Design, Multi-Turn Patterns | @modelcontextprotocol/sdk |
1617

1718
> Files marked with a replaceable library contain `[Replaceable]` notes at the top. The architectural principles remain the same regardless of the library chosen.

0 commit comments

Comments
 (0)