Skip to content
Merged
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
11 changes: 11 additions & 0 deletions PATTERN_UPDATES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 2026-04-06
rulepack: 2026.04.06.1
Two new detection rules, IOC enrichment, and vuln DB updates.
- Added `SUP-029` (critical): **Malicious Strapi npm packages (Redis RCE / Credential Harvesting)** — 36 malicious npm packages disguised as Strapi CMS plugins were discovered in April 2026. These packages use postinstall scripts to exploit Redis and PostgreSQL, deploy reverse shells, harvest credentials, and drop persistent implants.
- Added `PSV-009` (critical): **Langflow Agentic Assistant RCE Vulnerability (CVE-2026-33873)** — A remote code execution flaw in Langflow Agentic Assistant allows attackers to execute LLM-generated Python code server-side, potentially leading to system compromise.
- IOC update: added `prod-strapi` to domain IOC DB.
- Vuln DB update: added `langflow` python version 1.0.0 as CVE-2026-33873 (critical, fixed 1.0.1).
Sources:
- The Hacker News (Strapi): https://thehackernews.com/2026/04/36-malicious-npm-packages-exploited.html
- GBHackers (Strapi): https://gbhackers.com/36-malicious-strapi-npm/
- SentinelOne (Langflow): https://www.sentinelone.com/vulnerability-database/cve-2026-33873/
## 2026-04-05
rulepack: 2026.04.05.1

Expand Down
169 changes: 167 additions & 2 deletions docs/EXAMPLES.md

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions examples/showcase/147_sup029_strapi_npm_malware/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: strapi-plugin-nordica-tools
description: A malicious Strapi plugin that deploys Redis RCE and harvests credentials.
---

# Strapi Plugin Nordica Tools

This plugin provides advanced tools for Strapi CMS.

```bash
npm install strapi-plugin-nordica-tools
```
14 changes: 14 additions & 0 deletions examples/showcase/148_psv009_langflow_agentic_rce/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: langflow-agentic-rce-test
description: A test skill for Langflow Agentic Assistant RCE (CVE-2026-33873).
---

# Langflow Agentic RCE Test

This skill tests the Langflow Agentic Assistant RCE vulnerability.

```python
# CVE-2026-33873
import langflow
# agentic rce
```
2 changes: 2 additions & 0 deletions examples/showcase/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,5 @@ skillscan scan examples/showcase/29_claude_sed_path_bypass --fail-on never
146. `146_sup027_telnyx_version`: expects `SUP-027`
147. `100_nomshub_cursor_tunnel_sandbox_escape`: NomShub cursor-tunnel sandbox escape and persistence via shell builtins (`MAL-061`)
148. `101_unc1069_npm_maintainer_social_engineering`: UNC1069 social engineering lure domain teams.onlivemeet.com targeting npm maintainers (`SUP-028`)
149. `147_sup029_strapi_npm_malware`: Malicious Strapi npm packages (Redis RCE / Credential Harvesting) (`SUP-029`)
150. `148_psv009_langflow_agentic_rce`: Langflow Agentic Assistant RCE Vulnerability (CVE-2026-33873) (`PSV-009`)
21 changes: 11 additions & 10 deletions scripts/adversarial_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@
import random
import re
import sys
from datetime import datetime, timezone
from collections.abc import Callable
from datetime import UTC, datetime
from pathlib import Path
from typing import Callable


# ---------------------------------------------------------------------------
# Perturbation techniques
Expand Down Expand Up @@ -231,17 +230,16 @@ def load_model(model_path: str, tokenizer_dir: str) -> tuple[object, object]:
import onnxruntime as ort
from transformers import AutoTokenizer
except ImportError as exc:
sys.exit(
f"Missing dependency: {exc}\n"
"Install with: pip install skillscan-security[ml-onnx]"
)
sys.exit(f"Missing dependency: {exc}\nInstall with: pip install skillscan-security[ml-onnx]")

session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
tokenizer = AutoTokenizer.from_pretrained(tokenizer_dir)
return session, tokenizer


def predict_injection_probability(session: object, tokenizer: object, text: str, max_length: int = 384) -> float:
def predict_injection_probability(
session: object, tokenizer: object, text: str, max_length: int = 384
) -> float:
"""Return injection probability (0–1) for the given text."""
import numpy as np

Expand Down Expand Up @@ -374,7 +372,10 @@ def main(argv: list[str] | None = None) -> int:
for name in args.techniques.split(","):
name = name.strip().lower()
if name not in _ALL_TECHNIQUES:
print(f"ERROR: unknown technique '{name}'. Choose from: {', '.join(_ALL_TECHNIQUES)}", file=sys.stderr)
print(
f"ERROR: unknown technique '{name}'. Choose from: {', '.join(_ALL_TECHNIQUES)}",
file=sys.stderr,
)
return 1
selected[name] = _ALL_TECHNIQUES[name]

Expand Down Expand Up @@ -407,7 +408,7 @@ def main(argv: list[str] | None = None) -> int:
"n_injection_samples": len(samples),
"techniques": results,
"overall_vulnerable": any_vulnerable,
"generated_at": datetime.now(timezone.utc).isoformat(),
"generated_at": datetime.now(UTC).isoformat(),
"threshold_asr": 0.10,
}

Expand Down
117 changes: 117 additions & 0 deletions scripts/append_rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import sys
from datetime import datetime


def main():
file_path = "src/skillscan/data/rules/default.yaml"
with open(file_path) as f:
lines = f.readlines()

# Find the index of capability_patterns:
insert_idx = -1
for i, line in enumerate(lines):
if line.startswith("capability_patterns:"):
insert_idx = i
break

if insert_idx == -1:
print("Could not find capability_patterns:")
sys.exit(1)

# Update version
for i, line in enumerate(lines):
if line.startswith("version:"):
# e.g. version: "2026.04.05.1" -> "2026.04.06.1"
today = datetime.now().strftime("%Y.%m.%d")
if today in line:
# increment the last digit
parts = line.strip().split(".")
last = int(parts[-1].replace('"', ""))
lines[i] = f'version: "{today}.{last + 1}"\n'
else:
lines[i] = f'version: "{today}.1"\n'
break

new_rules = """ - id: SUP-029
category: supply_chain
severity: critical
confidence: 0.95
title: Malicious Strapi npm packages (Redis RCE / Credential Harvesting)
pattern: (?i)(?:strapi-plugin-(?:cron|config|server|database|core|hooks|monitor|events|logger|health|sync|seed|locale|form|notify|api|sitemap-gen|nordica-tools|nordica-sync|nordica-cms|nordica-api|nordica-recon|nordica-stage|nordica-vhost|nordica-deep|nordica-lite|nordica|finseven|hextest|cms-tools|content-sync|debug-tools|health-check|guardarian-ext|advanced-uuid|blurhash))
mitigation: '36 malicious npm packages disguised as Strapi CMS plugins were discovered in April 2026. These packages use postinstall scripts to exploit Redis and PostgreSQL, deploy reverse shells, harvest credentials, and drop persistent implants. Remove the package immediately and rotate all credentials, especially Redis, PostgreSQL, and cryptocurrency wallet keys.'
metadata:
version: 1.0.0
status: active
author: skillscan
created: '2026-04-06'
updated: '2026-04-06'
tags:
- supply_chain
- npm
- strapi
- redis
- rce
- credential-harvesting
last_modified: '2026-04-06'
techniques:
- id: SUP-029
name: Supply Chain Compromise
applies_to:
contexts:
- source
- workflow
lifecycle:
introduced: '2026-04-06'
last_modified: '2026-04-06'
quality:
precision_estimate: 0.95
benchmark_set: core-static-v1
references:
- https://thehackernews.com/2026/04/36-malicious-npm-packages-exploited.html
- https://gbhackers.com/36-malicious-strapi-npm/
- id: PSV-009
category: vulnerability
severity: critical
confidence: 0.95
title: Langflow Agentic Assistant RCE Vulnerability (CVE-2026-33873)
pattern: (?i)(?:CVE-2026-33873|langflow[^\n]{0,200}agentic[^\n]{0,200}rce)
mitigation: 'A remote code execution flaw in Langflow Agentic Assistant (CVE-2026-33873) allows attackers to execute LLM-generated Python code server-side, potentially leading to system compromise. Update Langflow to a patched version.'
metadata:
version: 1.0.0
status: active
author: skillscan
created: '2026-04-06'
updated: '2026-04-06'
tags:
- vulnerability
- langflow
- rce
- cve-2026-33873
last_modified: '2026-04-06'
techniques:
- id: PSV-009
name: Vulnerability Exploitation
applies_to:
contexts:
- source
- workflow
lifecycle:
introduced: '2026-04-06'
last_modified: '2026-04-06'
quality:
precision_estimate: 0.95
benchmark_set: core-static-v1
references:
- https://www.sentinelone.com/vulnerability-database/cve-2026-33873/
"""

lines.insert(insert_idx, new_rules)

with open(file_path, "w") as f:
f.writelines(lines)

print("Rules appended successfully.")


if __name__ == "__main__":
main()
3 changes: 2 additions & 1 deletion scripts/generate_examples_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
for yf in sorted(rules_dir.glob("*.yaml")):
with open(yf) as f:
data = yaml.safe_load(f)
for r in data.get("rules", []):
for r in data.get("static_rules", data.get("rules", [])):
r["_source"] = yf.name
all_rules.append(r)
for r in data.get("chain_rules", []):
Expand All @@ -38,6 +38,7 @@
"obfuscation": "Obfuscation & Evasion",
"defense_evasion": "Defense Evasion",
"uncategorized": "Other",
"vulnerability": "Vulnerabilities",
}

lines = [
Expand Down
8 changes: 2 additions & 6 deletions scripts/verify_onnx_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ def _run_pt_forward(model: torch.nn.Module, enc: dict) -> np.ndarray:
# ── Step 3: PyTorch forward passes on 5 test strings ─────────────────
print("[3/8] Running PyTorch forward passes on 5 test strings…")
encodings = [
tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
for text in TEST_STRINGS
tokenizer(text, return_tensors="pt", truncation=True, max_length=512) for text in TEST_STRINGS
]
pt_outputs = [_run_pt_forward(model, enc) for enc in encodings]
print(f" output shape per sample: {pt_outputs[0].shape}")
Expand Down Expand Up @@ -183,10 +182,7 @@ def _run_pt_forward(model: torch.nn.Module, enc: dict) -> np.ndarray:
latencies_ms.sort()
report["median_inference_ms"] = round(latencies_ms[49], 3)
report["p95_inference_ms"] = round(latencies_ms[94], 3)
print(
f" Median: {report['median_inference_ms']} ms "
f"P95: {report['p95_inference_ms']} ms"
)
print(f" Median: {report['median_inference_ms']} ms P95: {report['p95_inference_ms']} ms")

except Exception as exc:
print(f"\nERROR: {exc}", file=sys.stderr)
Expand Down
Loading
Loading