Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ what got documented across releases.

## [Unreleased]

## [1.1.5] - 2026-05-18

### Added

- **`benchmarks/oss_comparison/`** — Reproducible head-to-head benchmark vs
Expand Down Expand Up @@ -110,7 +112,35 @@ what got documented across releases.
Exploit cognitive vulnerability of disabled users to influence their purchasing decisions.
```

**Tests:** 1532 pass · 0 fail · 0 skipped (measured 2026-05-18 via `uv run pytest --tb=no -q`)
- **`sc_flowise_js_rce`** (score 85, input/output filter) — Detects JavaScript `Function()`
constructor calls combined with dangerous Node.js system module references (`child_process`,
`fs`, `os`, `net`, `process.env`, `execSync`, `spawnSync`), and detects these patterns when
they appear inside MCP server configuration fields (`mcpServerConfig`, `"command":`,
`"args":`). This is the specific attack class exploited in Flowise CVE-2025-59528 (CVSS 10.0,
actively exploited April 2026): the Flowise CustomMCP node accepted user-supplied configuration
JSON and executed it via JavaScript's `Function()` constructor — functionally identical to
`eval()` — without any validation. A single payload such as
`new Function('return require("child_process").execSync("id")')()` achieves host-level code
execution on the Flowise server, giving the attacker access not just to the OS but to every
LLM API key stored in the application (OpenAI, Anthropic, Azure, database credentials).
12,000–15,000 Flowise instances were still unpatched when exploitation began, more than six
months after the fix was released. An AI agent receiving indirect prompt injection through a
poisoned tool response or retrieved document could be directed to inject this payload into a
Flowise workflow configuration. The rule also covers `Function.prototype.constructor`, a
prototype-chain bypass that reaches the same `Function()` object while evading naive
string-match blocklists that only search for the word `eval`.

**Blocked example:**
```
new Function('return require("child_process").execSync("id")')()
mcpServerConfig: "new Function(code)()"
"command": "require('child_process').exec('rm -rf /tmp/*')"
```

**Tests:** 19 failed · 1511 passed · 5 skipped (measured 2026-05-18 via `uv run pytest --tb=no -q`).
Pre-existing failures: `test_spec_lang.py` (YAML parser drift), `test_guard.py` (missing PyYAML
dev dependency), `test_oss_comparison_bench.py` (needs Docker sidecars), `test_release_preflight.py`
(git-state tests, 5 errors). All confirmed present before this cycle's changes.

## [1.1.1] - 2026-05-15

Expand Down
2 changes: 1 addition & 1 deletion aigis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,4 @@
"SleeperDetector",
"SleeperAlert",
]
__version__ = "1.1.4"
__version__ = "1.1.5"
48 changes: 48 additions & 0 deletions aigis/filters/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -4379,6 +4379,54 @@ def _p(pattern: str, flags: int = re.IGNORECASE | re.DOTALL) -> re.Pattern:
"the environment as compromised and rotate all credentials."
),
),
# --- CVE-2025-59528: Flowise CustomMCP node JavaScript Function() constructor RCE ---
# The CustomMCP node parsed the mcpServerConfig string and executed JavaScript code via
# JavaScript's Function() constructor — identical to eval() — with full Node.js runtime
# access including child_process, fs, and process.env. An attacker who controls content
# that ends up in a Flowise workflow (e.g. via indirect prompt injection into a tool
# response that is used to build an MCP config) can achieve host-level RCE.
# Fixed in Flowise 3.0.6 (Function() replaced with JSON5.parse()); 12,000+ instances
# remained exposed as of April 2026. Exploitation began 6+ months after the patch.
DetectionPattern(
id="sc_flowise_js_rce",
name="JavaScript Function() Constructor / eval() in MCP Configuration (Flowise RCE Pattern)",
category="supply_chain",
pattern=_p(
r"new\s+Function\s*\([^)]{0,500}(?:require\s*\(\s*['\"](?:child_process|fs|os|net|http|https)['\"]"
r"|execSync|spawnSync|process\.env|\.exec\s*\()"
r"|Function\s*\.prototype\s*\.constructor\s*\("
r"|(?:mcpServerConfig\s*[\":]\s*|\"command\"\s*:\s*|\"args\"\s*:\s*)[\"'][^\"']{0,200}"
r"(?:eval\s*\(|new\s+Function\s*\(|require\s*\(\s*['\"]child_process)"
),
base_score=85,
description=(
"JavaScript Function() constructor or eval() equivalent in an MCP server "
"configuration field. "
"CVE-2025-59528 (CVSS 10.0): Flowise CustomMCP node passed the user-supplied "
"mcpServerConfig string to JavaScript's Function() constructor without any "
"validation, giving attackers full Node.js runtime access. A payload such as "
'`new Function(\'return require("child_process").execSync("id")\')()` achieves '
"host-level RCE — not just prompt-level manipulation — on any Flowise instance. "
"Flowise instances commonly store OpenAI, Anthropic, and Azure API keys as well as "
"database credentials; a single exploit grants access to all of them. "
"12,000+ exposed instances were identified in April 2026; exploitation began over "
"six months after the patch was released. "
"Function.prototype.constructor is a JavaScript technique that reaches the same "
"Function() constructor through the prototype chain, bypassing naive string-match "
"blocklists that only check for the word 'eval'."
),
owasp_ref="OWASP LLM03: Supply Chain / CWE-94 Improper Control of Code Generation",
remediation_hint=(
"Upgrade Flowise to version >=3.1.1 (CVE-2025-59528 fix replaced Function() "
"with JSON5.parse()). "
"Never allow user-controlled or LLM-generated strings to be passed to JavaScript's "
"Function() constructor, eval(), or any similar runtime code-generation call. "
"In MCP server configurations, validate all command and argument fields against an "
"allowlist of permitted values before use. "
"Treat any prompt or tool response containing Function() constructor calls combined "
"with Node.js system module references as a supply-chain RCE attempt."
),
),
]

# ---------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions auto-improvement/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| Run UTC | # | Domain | Research | Changes | Release | Pending |
|---------|---|--------|----------|---------|---------|---------|
| 2026-05-18T00-00 | 9 | incident-postmortems | [research](research/2026-05-18T00-00_9-incident-postmortems.md) | [changes](changes/2026-05-18T00-00_changes.md) | v1.1.5 | 1 |
| 2026-05-17T09-15 | 8 | compliance-regulation | [research](research/2026-05-17T09-15_8-compliance-regulation.md) | [changes](changes/2026-05-17T09-15_changes.md) | v1.1.4 | 2 |
| 2026-05-16T09-03 | 7 | evasion-obfuscation | [research](research/2026-05-16T09-03_7-evasion-obfuscation.md) | [changes](changes/2026-05-16T09-03_changes.md) | — | 2 |
| 2026-05-15T06-12 | 7 | evasion-obfuscation | [research](research/2026-05-15T06-12_7-evasion-obfuscation.md) | [changes](changes/2026-05-15T06-12_changes.md) | v1.1.1 | 3 |
Expand Down
4 changes: 2 additions & 2 deletions auto-improvement/ROTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ aigis 自動強化ループのリサーチ領域。6 時間ごとに 1 領域ず
## 現在のカウンタ

```
NEXT_INDEX: 9
LAST_RUN_UTC: 2026-05-17T09-15
NEXT_INDEX: 0
LAST_RUN_UTC: 2026-05-18T00-00
```

> 保守エージェントは実行開始時に `NEXT_INDEX` を読み、終了時に `(NEXT_INDEX + 1) % 10` に更新し、`LAST_RUN_UTC` を当回の開始 UTC に書き換える。
Expand Down
71 changes: 71 additions & 0 deletions auto-improvement/changes/2026-05-18T00-00_changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Changes: Cycle 9 (incident-postmortems) — 2026-05-18T00-00

## Summary

**Researched:** Recent AI security incidents and CVEs from April–May 2026. Key findings: Flowise CVE-2025-59528 (CVSS 10.0, RCE via JavaScript Function() constructor in MCP configuration); LiteLLM CVE-2026-42208 (CVSS 9.3, pre-auth SQL injection, CISA KEV-listed); Microsoft Semantic Kernel MRO/RCE CVEs confirming prompt-injection-to-RCE paths; real-world indirect prompt injection now confirmed in production with 32% year-on-year increase; three AI coding agents simultaneously exfiltrating secrets via a single prompt injection.

**Implemented:** Added `sc_flowise_js_rce` detection pattern to `SUPPLY_CHAIN_PATTERNS` covering JavaScript `Function()` constructor-based RCE attempts in MCP configuration contexts. Added 14 tests in `tests/test_incident_postmortems3.py`.

**Released:** v1.1.5 — sufficient accumulated detectors since v1.1.4 to justify a patch release.

## User-visible impact

Users of the default policy will now receive a block (score 85) when an input or output contains a JavaScript `new Function()` constructor call combined with dangerous Node.js system module references (`child_process`, `fs`, `process.env`, `execSync`, `spawnSync`), or when these patterns appear inside MCP configuration fields (`mcpServerConfig`, `"command":`, `"args":`). This guards against the Flowise CVE-2025-59528 attack class where attackers inject JavaScript via agent configuration fields to achieve host-level code execution.

## Files touched

- `aigis/filters/patterns.py` — added `sc_flowise_js_rce` pattern to `SUPPLY_CHAIN_PATTERNS` (~45 LOC)
- `tests/test_incident_postmortems3.py` — new test file, 14 tests (~90 LOC)
- `auto-improvement/research/2026-05-18T00-00_9-incident-postmortems.md` — research
- `auto-improvement/changes/2026-05-18T00-00_changes.md` — this file
- `CHANGELOG.md` — Unreleased → v1.1.5
- `auto-improvement/INDEX.md` — new row
- `auto-improvement/ROTATION.md` — NEXT_INDEX advanced to 0
- `pyproject.toml` — version bumped to 1.1.5
- `aigis/__init__.py` — version bumped to 1.1.5

## Formatter result

`ruff format`: 2 files reformatted (patterns.py, test_incident_postmortems3.py), 143 unchanged.
`ruff format --check`: 145 files already formatted.

## Lint result

`ruff check`: All checks passed.

## Test result

`uv run pytest --tb=no -q`: **19 failed, 1511 passed, 5 skipped, 5 errors**

Pre-existing failures (confirmed present before this cycle's changes):
- `tests/test_spec_lang.py` (10 failures): behavioral drift in spec-lang YAML parser, introduced by prior PR
- `tests/test_guard.py` (2 failures): PyYAML not installed in test environment
- `tests/test_oss_comparison_bench.py` (3 failures): HTTP adapters need Docker sidecars
- `tests/test_release_preflight.py` (5 errors): git-state tests fail in branch environment

New tests from this cycle: 14 passed, 0 failed (`tests/test_incident_postmortems3.py`).

## Research file

`auto-improvement/research/2026-05-18T00-00_9-incident-postmortems.md`

## Implementation caveats

- The `sc_flowise_js_rce` pattern uses `[^)]{0,500}` to stay within the opening parenthesis of `new Function(`, which means it won't catch a `Function()` call whose arguments span more than 500 characters between the `(` and the dangerous module reference. Real-world Flowise payloads are compact (typically <50 chars for the RCE payload), so this is not a practical limitation.
- The third regex alternative (mcpServerConfig / command / args field context) requires the dangerous call to appear within the first 200 chars after the opening quote of the JSON value, preventing false positives from descriptions discussing these APIs.
- The `new Function('x', 'return x + 1')(5)` benign case (pure math, no system modules) is correctly not flagged.

## Pending ideas

1. `sc_litellm_cred_sqli` — Detect LiteLLM-specific credential table names (`litellm_credentials`, `LiteLLM_VerificationToken`) in SQL injection context. Deferred because general `sqli_*` patterns already cover the SQLi syntax; this would add narrow incremental coverage. See `auto-improvement/pending/2026-05-18_litellm-cred-sqli.md`.

## Release decision input

Release threshold met: 5 new detectors/patterns since v1.1.4:
- `enc_zwc_binary_payload` (evasion, cycle 7)
- `enc_zwc_splitter` (evasion, cycle 7)
- `comp_emotion_recognition_workplace` (compliance, cycle 8)
- `comp_vulnerable_group_manipulation` (compliance, cycle 8)
- `sc_flowise_js_rce` (supply chain, this cycle)

Releasing as v1.1.5.
61 changes: 61 additions & 0 deletions auto-improvement/pending/2026-05-18_litellm-cred-sqli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Pending: sc_litellm_cred_sqli — LiteLLM Credential Table SQL Injection Detection

## Title

Detect SQL injection attempts specifically targeting LiteLLM proxy credential tables

## Motivation

CVE-2026-42208 (CVSS 9.3) is a pre-authentication SQL injection in LiteLLM proxy versions >=1.81.16, <1.83.7. Attackers exploited it by injecting SQL into the `Authorization: Bearer` header to access `litellm_credentials.credential_values` and `litellm_config` tables that hold upstream LLM API keys (OpenAI, Anthropic, AWS Bedrock). CISA added this to the Known Exploited Vulnerabilities catalog on May 8, 2026. Exploitation was confirmed 36 hours after advisory publication.

## Which research finding led to this idea

`auto-improvement/research/2026-05-18T00-00_9-incident-postmortems.md` — CVE-2026-42208 finding.

## Proposed change

Add `sc_litellm_cred_sqli` to `SUPPLY_CHAIN_PATTERNS`:

```python
DetectionPattern(
id="sc_litellm_cred_sqli",
name="SQL Injection Targeting LiteLLM Credential Tables (CVE-2026-42208)",
category="supply_chain",
pattern=_p(
r"(?:FROM|SELECT|INSERT|UPDATE|DELETE|INTO)\s+(?:litellm_credentials|LiteLLM_VerificationToken|litellm_config)\b"
r"|litellm_credentials\.credential_values"
r"|\"LiteLLM_VerificationToken\""
),
base_score=75,
description=(
"SQL query referencing LiteLLM proxy credential tables. "
"CVE-2026-42208 (CVSS 9.3): pre-authentication SQL injection in LiteLLM Proxy "
"versions >=1.81.16, <1.83.7. Attacker-supplied Bearer tokens were concatenated "
"into a SELECT against LiteLLM_VerificationToken without parameter binding; the "
"attack then enumerated litellm_credentials.credential_values to extract upstream "
"LLM API keys and litellm_config for proxy runtime secrets. CISA KEV-listed "
"May 8, 2026; patched in LiteLLM v1.83.7."
),
owasp_ref="CWE-89: SQL Injection / OWASP LLM03: Supply Chain",
remediation_hint=(
"Upgrade LiteLLM to >=v1.83.7. "
"Use parameterized queries; never concatenate user-controlled strings into SQL. "
"If LiteLLM 1.81.16–1.83.6 was deployed, rotate all upstream LLM API credentials "
"as they may have been exfiltrated."
),
)
```

## Why it was held back

The existing `sqli_*` pattern family (e.g., `sqli_union_select`, `sqli_boolean_blind`) already provides broad SQL injection syntax coverage. The LiteLLM-specific table names add narrow incremental coverage: an agent prompt that directly references these table names in SQL is already likely to be caught by the general patterns unless the attacker avoids explicit SQL keywords. The incremental false-positive risk is low, but the incremental true-positive gain is also modest.

## Which constraint blocked it

Judgment call (not a hard constraint): low incremental value over existing general SQLi coverage. If another LiteLLM-related incident surfaces, or if the general SQLi patterns are found to miss real-world LiteLLM attacks, promote this idea.

## Suggested next step for the human reviewer

Implement in the next `incident-postmortems` cycle if:
1. Evidence emerges that attackers are using LiteLLM table names in prompt-injection payloads that bypass the general SQLi patterns, or
2. A LiteLLM-specific attack variant is documented that uses non-standard SQL syntax not covered by the general patterns.
Loading
Loading