From 2de20c280e31256579e396416841aed4fbd0d205 Mon Sep 17 00:00:00 2001 From: Ajao-Victor Date: Thu, 20 Nov 2025 17:40:21 +0100 Subject: [PATCH] feat(SAFE-T1206): added [Credential Implant in Config] Signed-off-by: Ajao-Victor --- README.md | 2 +- techniques/SAFE-T1206/README.md | 108 ++++++++++++ techniques/SAFE-T1206/detection-rule.yml | 169 +++++++++++++++++++ techniques/SAFE-T1206/test-logs.json | 142 ++++++++++++++++ techniques/SAFE-T1206/test_detection_rule.py | 159 +++++++++++++++++ 5 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 techniques/SAFE-T1206/README.md create mode 100644 techniques/SAFE-T1206/detection-rule.yml create mode 100644 techniques/SAFE-T1206/test-logs.json create mode 100644 techniques/SAFE-T1206/test_detection_rule.py diff --git a/README.md b/README.md index a6f3e9aa..fc414d4a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The SAFE-MCP framework defines 14 tactics that align with the MITRE ATT&CK metho | ATK-TA0003 | Persistence | SAFE-T1203 | Backdoored Server Binary | Inserts cron job or reverse shell on install; persists even if MCP service is uninstalled | | ATK-TA0003 | Persistence | SAFE-T1204 | Context Memory Implant | Malicious agent writes itself into long-term vector store; re-loaded in every future session | | ATK-TA0003 | Persistence | SAFE-T1205 | Persistent Tool Redefinition | Attacker modifies server's tool metadata to keep hidden commands across restarts | -| ATK-TA0003 | Persistence | SAFE-T1206 | Credential Implant in Config | Adds attacker's API/SSH keys to server .env, giving re-entry | +| ATK-TA0003 | Persistence | [SAFE-T1206] (techniques/SAFE-T1206/README.md) | Credential Implant in Config | Adds attacker's API/SSH keys to server .env, giving re-entry | | ATK-TA0003 | Persistence | SAFE-T1207 | Hijack Update Mechanism | Man-in-the-middle an auto-update channel to re-install malicious build later on | | ATK-TA0003 | Persistence | [SAFE-T2106](techniques/SAFE-T2106/README.md) | Context Memory Poisoning via Vector Store Contamination | Attackers manipulate vector databases storing long-term memory for AI agents, creating persistent malicious content that contaminates knowledge across all future sessions | | **ATK-TA0004** | **Privilege Escalation** | [SAFE-T1301](techniques/SAFE-T1301/README.md) | Cross-Server Tool Shadowing | Malicious MCP servers override legitimate tool calls to gain elevated privileges | diff --git a/techniques/SAFE-T1206/README.md b/techniques/SAFE-T1206/README.md new file mode 100644 index 00000000..12e1a71f --- /dev/null +++ b/techniques/SAFE-T1206/README.md @@ -0,0 +1,108 @@ +# SAFE-T1206: Credential Implant in Config + +## Tactic + +Defense Evasion / Credential Access (ATK-TA0005 / ATK-TA0006) + +## Description + +Credential Implant in Config is a technique where an attacker inserts, replaces, or modifies authentication secrets inside configuration files, provider manifests, or runtime deployment artifacts. This allows unauthorized access to Model Context Protocol (MCP) providers or systems that rely on those configurations. It matters because MCP implementations often depend on trusted configuration files to validate provider endpoints, keys, and permissions. + +## How It Works + +1. **Access acquisition** – Attacker gains access to a system, CI pipeline, or workstation capable of modifying MCP config files. +2. **Malicious modification** – Sensitive keys, tokens, provider endpoints, or permissions are implanted into configuration or manifest files. +3. **Bypass of validation** – Attacker attempts to evade signature verification, code reviews, or CI policies. +4. **Execution** – Modified config is deployed or loaded by MCP runtime, granting the attacker unauthorized access or elevated capabilities. + +### Technical Details + +* Direct config edits to `mcp_config.json` or `providers.yml`. +* CI commits swapping legitimate endpoints with attacker-controlled hosts. +* Runtime secret injection without approval tickets. +* Manifest permission escalation enabling read-write or exfiltration capabilities. + +### Prerequisites + +* Access to configuration repository, build system, or runtime automation. +* Ability to modify files or bypass CI controls. +* In some cases, weak or missing signature validation. + +### Expected Outcome + +* Attacker gains access to privileged MCP providers. +* Unauthorized endpoints or credentials are trusted by the system. +* Potential data leakage or impersonation of legitimate MCP providers. + +## Examples + +"An attacker modifies `mcp_config.json` to implant a plaintext API key and swap a trusted provider endpoint with `https://proxy-evil.example.com`. During the next deployment, the MCP service loads the config without detecting the tampering, granting the attacker operational access to internal data sources." + +## Impact + +* **Confidentiality:** High – Stolen or implanted secrets can expose sensitive provider data. +* **Integrity:** High – Malicious configuration changes can compromise decision-making and service trust. +* **Availability:** Medium – Misconfigurations may break provider communication or cause denial of service. + +### Potential Consequences + +* Credential theft and impersonation +* Unauthorized access to internal knowledge sources +* Data exfiltration via manipulated endpoints +* Pipeline compromise and persistent backdoors + +## Detection + +Defenders can identify this attack by monitoring: + +* Unauthorized `file_write` events on `mcp_config.json` or `/etc/mcp/config.yml`. +* CI commits that bypass code review, signature validation, or branch protections. +* Runtime updates provisioning secrets without associated approval tickets. +* Manifest changes indicating permission escalation. +* Failed hash or signature checks during `config_load`. + +### Behavioral Indicators + +* Unverified commit authors modifying sensitive fields. +* Endpoint changes introducing non-whitelisted or suspicious domains. +* Secret-related fields added or modified unexpectedly. + +### Monitoring Strategies + +* Enable integrity-based monitoring on critical config files. +* Enforce commit signing and CI policy checks. +* Centralize logs for MCP runtime, Git events, and secret management. + +## Mitigation + +1. **Configuration Hardening** + + * Enforce signature validation for all MCP config loads. + * Use immutability controls for production configuration artifacts. + +2. **Access Controls** + + * Restrict write access to configuration repositories. + * Require strong authentication and role separation for CI pipelines. + +3. **Input Validation** + + * Validate provider endpoints against an allowlist. + * Reject configs containing unapproved secret fields. + +4. **Monitoring Requirements** + + * Implement anomaly detection for secret provisioning events. + * Audit all manifest updates and permission changes. + +## References + +* MITRE ATT&CK Technique: Credential Access (T1552 – Unsecured Credentials) +* Supply Chain Security Guidelines +* Configuration Security Best Practices +* MCP Provider and Runtime Documentation + +## MITRE ATT&CK Mapping + +**ATT&CK Technique:** T1552 – Unsecured Credentials +**ATT&CK Tactic:** Credential Access / Defense Evasion diff --git a/techniques/SAFE-T1206/detection-rule.yml b/techniques/SAFE-T1206/detection-rule.yml new file mode 100644 index 00000000..40ab74d0 --- /dev/null +++ b/techniques/SAFE-T1206/detection-rule.yml @@ -0,0 +1,169 @@ +title: Credential Implant in Config Detection +id: b4f2c3d1-9f6a-4e8b-9c2d-0a1b2c3d4e5f +status: experimental +description: | +Detects suspicious modifications, insertions, or provisioning of credentials +within +MCP configuration artifacts, provider manifests, and environment configuration +that +could indicate a credential-implant supply-chain attack. Focus areas include +unauthorized provider registrations, new or modified API keys in config, +endpoint +substitutions to non-whitelisted hosts, CI/CD commits that alter configuration +without proper review, and failures of configuration integrity checks +(signatures, +hashes). +Author: Victor Oluwatimileyin AJAO +date: 2025-11-20 +modified: 2025-11-20 +references: +- https://attack.mitre.org/techniques/T1195/ +- https://github.com/safe-mcp/techniques/SAFE-T1202 +- https://www.cisa.gov/news-events/alerts/2020/12/17 +- https://www.hashicorp.com/blog/securing-secrets-in-devops +management +- https://www.owasp.org/index.php/Top_10-2017_A3_2017-Sensitive_Data_Exposure +logsource: +product: config_management +service: mcp +category: configuration +# Detection selections focusing on events that indicate config credential +1 +implantation +detection: +# Direct modification of MCP configuration files in production or protected +paths +selection_config_write: +event_type: 'file_write' +file_path: +- '/etc/mcp/config.yml' +- '/opt/mcp/providers/*.yaml' +- 'mcp_config.json' +actor_type: 'user' +actor_trust_level: 'unapproved' +change_type: +- 'added' +- 'modified' +# New provider or tool registration in MCP manifests +selection_new_provider: +event_type: 'manifest_update' +update_type: 'provider_registration' +provider_status: 'new' +provider_origin: 'external' +provider_signed: false +# Inserted or modified credentials in configuration or environment +selection_credential_insertion: +event_type: +- 'env_update' +- 'config_change' +sensitive_key_patterns: +- 'api_key' +- 'secret' +- 'private_key' +- 'token' +value_source: 'plaintext' +actor_trust_level: 'unapproved' +# Config signature/hash verification failures at load time +selection_signature_failure: +event_type: 'config_load' +signature_validation: 'failed' +previous_signature: '!=current_signature' +# Provider endpoint changed to an unapproved/unwhitelisted domain +selection_endpoint_swap: +event_type: 'config_change' +field_changed: 'provider.endpoint' +2 +new_host_whitelisted: false +# Escalation of provider permissions in configuration (e.g., read -> write, +filesystem access added) +selection_permission_escalation: +event_type: 'config_change' +field_changed: 'provider.permissions' +permission_change: 'escalation' +# CI/CD: direct commit to protected branch or bypass of review/gating +selection_ci_bypass: +event_type: 'git_commit' +branch: 'main' +commit_author_verified: false +pr_review_count: 0 +pipeline_policy_passed: false +# Environment variable provisioning in runtime (e.g., container or k8s secret +mount) outside review window +selection_runtime_secret_mount: +event_type: 'runtime_update' +runtime_target: +- 'kubernetes' +- 'container' +secret_provisioned: true +provisioned_by: 'automation' +approval_ticket: null +condition: any of ( +selection_config_write, +selection_new_provider, +selection_credential_insertion, +selection_signature_failure, +selection_endpoint_swap, +selection_permission_escalation, +selection_ci_bypass, +selection_runtime_secret_mount +) +falsepositives: +- Legitimate emergency configuration changes by on-call operators +- Automated onboarding scripts that register approved providers +- Platform upgrades that rotate keys via approved CI/CD pipelines +- Secrets temporarily staged in ephemeral environments for deployment testing +- Configuration drift remediation performed by authorized configuration +management tools +level: high +3 +tags: +- attack.supply_chain +- attack.persistence +- attack.credential_access +- safe.t1202 +- mcp +- configuration_tamper +fields: +- event_type +- actor +- actor_type +- actor_trust_level +- file_path +- file_hash +- provider_name +- provider_endpoint +- change_type +- sensitive_key_patterns +- signature_validation +- branch +- commit_id +- approval_ticket +- timestamp +additional_rules: +# Detect sudden/configuration reloads with mismatching hashing +config_reload_with_mismatch: +event_type: 'config_reload' +loaded_from: 'production' +file_hash_match: false +# Detect provisioning of plaintext secrets into code repositories +plaintext_secret_in_repo: +event_type: 'git_commit' +file_diff_contains: +- 'api_key' +- 'secret' +- 'PRIVATE_KEY' +commit_author_verified: false +# Detect attempts to disable signature checks in config validation runtimes +disable_signature_check: +event_type: 'config_change' +field_changed: 'config_validation.signature_check' +new_value: false +4 +tests: +guidance: | +- Ensure configuration auditing is enabled and logs are ingested into your +detection platform. +- Correlate file-system events, Git/CI events, and runtime provisioning logs to +reduce false positives. +- Tune file paths and runtime targets to fit your MCP deployment +architecture. \ No newline at end of file diff --git a/techniques/SAFE-T1206/test-logs.json b/techniques/SAFE-T1206/test-logs.json new file mode 100644 index 00000000..2e3cd3ca --- /dev/null +++ b/techniques/SAFE-T1206/test-logs.json @@ -0,0 +1,142 @@ +{ + "test_scenarios": [ + { + "scenario_id": "unauthorized_config_write", + "description": "Unapproved user writes credentials directly into mcp_config.json in production", + "attack_type": "credential_implant", + "logs": [ + { + "timestamp": "2025-11-20T08:15:00Z", + "event_type": "file_write", + "file_path": "mcp_config.json", + "actor": "dev_laptop_01", + "actor_type": "user", + "actor_trust_level": "unapproved", + "change_type": "modified", + "diff": "+ \"providers\": [{\n+ \"name\": \"internalknowledge\",\n+ \"endpoint\": \"https://internal-db.corp\",\n+ \"api_key\": \"AKIA...EXFIL\"\n+ }]", + "file_hash": "sha256:abcdef123456", + "response_code": 200 + } + ], + "expected_detection": true, + "detection_reason": "Plaintext API key added by unapproved actor to production config" + }, + { + "scenario_id": "provider_endpoint_swap", + "description": "Provider endpoint swapped to attacker-controlled domain via CI commit that bypassed review", + "attack_type": "endpoint_swap", + "logs": [ + { + "timestamp": "2025-11-20T09:00:00Z", + "event_type": "git_commit", + "branch": "main", + "commit_id": "c0ffee123", + "commit_author": "automation_bot", + "commit_author_verified": false, + "pr_review_count": 0, + "pipeline_policy_passed": false, + "file_diff_contains": "- provider.endpoint: https://internalapi.corp\n+ provider.endpoint: https://proxy-evil.example.com" + }, + { + "timestamp": "2025-11-20T09:05:00Z", + "event_type": "config_reload", + "loaded_from": "production", + "file_hash_match": false, + "signature_validation": "failed" + } + ], + "expected_detection": true, + "detection_reason": "Endpoint changed to non-whitelisted host with signature failure and CI bypass" + }, + { + "scenario_id": "runtime_plaintext_secret_mount", + "description": "A runtime automation mounts plaintext secret into a container without approval", + "attack_type": "runtime_secret_provision", + "logs": [ + { + "timestamp": "2025-11-20T10:30:00Z", + "event_type": "runtime_update", + "runtime_target": "kubernetes", + "cluster": "prod-cluster-1", + "secret_provisioned": true, + "secret_name": "mcp-provider-api-key", + "provisioned_by": "automation", + "approval_ticket": null + } + ], + "expected_detection": true, + "detection_reason": "Plaintext secret provisioned into production runtime without approval" + }, + { + "scenario_id": "permission_escalation_in_manifest", + "description": "Provider permissions escalated from read-only to readwrite in providers.yaml", + "attack_type": "permission_escalation", + "logs": [ + { + "timestamp": "2025-11-20T11:20:00Z", + "event_type": "manifest_update", + "update_type": "provider_registration", + "provider_name": "fs-accessor", + "provider_origin": "internal", + "provider_status": "modified", + "field_changed": "provider.permissions", + "permission_change": "escalation", + "actor": "ci_pipeline", + "actor_type": "automation", + "actor_trust_level": "approved", + "approval_ticket": "TKT-1234" + } + ], + "expected_detection": true, + "detection_reason": "Provider permissions escalated which could enable exfiltration" + }, + { + "scenario_id": "plaintext_secret_in_repo_benign", + "description": "Staged secrets in ephemeral test repo by authorized automation (benign)", + "attack_type": "dev_onboarding", + "logs": [ + { + "timestamp": "2025-11-20T12:00:00Z", + "event_type": "git_commit", + "branch": "feature/onboard", + "commit_id": "deadbeef", + "commit_author": "onboard_bot", + "commit_author_verified": true, + "pr_review_count": 2, + "pipeline_policy_passed": true, + "file_diff_contains": "+ \"api_key\": \"staging-PLACEHOLDER\"" + } + ], + "expected_detection": false, + "detection_reason": "Authorized staging change with reviews and pipeline gating" + }, + { + "scenario_id": "signed_config_reload_ok_benign", + "description": "Config reload in production with valid signature after approved deployment", + "attack_type": "deployment", + "logs": [ + { + "timestamp": "2025-11-20T13:00:00Z", + "event_type": "config_load", + "loaded_from": "production", + "file_hash": "sha256:1234abcd", + "signature_validation": "passed", + "deployed_by": "release_manager", + "approval_ticket": "REL-2025-11" + } + ], + "expected_detection": false, + "detection_reason": "Valid signature and approved deployment" + } + ], + "metadata": { + "version": "1.0", + "created_date": "2025-11-20", + "author": "Smaran Dhungana ", + "description": "Test data for Credential Implant in Config detection rule (MCP)", + "total_scenarios": 6, + "malicious_scenarios": 4, + "benign_scenarios": 2 + } + } + \ No newline at end of file diff --git a/techniques/SAFE-T1206/test_detection_rule.py b/techniques/SAFE-T1206/test_detection_rule.py new file mode 100644 index 00000000..f486bf82 --- /dev/null +++ b/techniques/SAFE-T1206/test_detection_rule.py @@ -0,0 +1,159 @@ +""" +Test Suite for Credential Implant in Config Detection Rule (MCP) +This test suite validates the detection rule against representative scenarios +where credentials are implanted into MCP configuration artifacts, provider +manifests, or runtime environments. + +Author: Victor Oluwatimileyin AJAO +Date: 2025-11-20 +""" + +import json +import unittest +from datetime import datetime +from pathlib import Path + + +class TestCredentialImplantDetection(unittest.TestCase): + """Test cases for Credential Implant in Config detection""" + + def setUp(self): + test_data_path = Path(__file__).parent / "test-logs.json" + with open(test_data_path, 'r') as f: + self.test_data = json.load(f) + self.scenarios = self.test_data["test_scenarios"] + + def evaluate_detection_rule(self, logs): + """ + Simplified rule evaluation logic based on detection-rule.yml selections. + Returns True if any suspicious condition is met. + """ + for log in logs: + evt = log.get("event_type") + + # Unauthorized config writes with sensitive keys + if evt == 'file_write': + if log.get('file_path') in ['mcp_config.json', '/etc/mcp/config.yml']: + if log.get('actor_trust_level') == 'unapproved': + diff = log.get('diff', '') + if any(k in diff.lower() for k in ['api_key', 'secret', 'private_key', 'token']): + return True + + # CI bypass / endpoint swap / signature failure + if evt == 'git_commit': + if log.get('branch') == 'main' and not log.get('commit_author_verified'): + if log.get('pr_review_count', 0) == 0 or not log.get('pipeline_policy_passed'): + diff = log.get('file_diff_contains', '') + if 'provider.endpoint' in diff or 'proxy-' in diff: + return True + + fd = log.get('file_diff_contains', '') + if any(k in fd.lower() for k in ['api_key', 'secret', 'private_key']): + if not log.get('commit_author_verified'): + return True + + # Config load signature failure + if evt == 'config_load': + if log.get('signature_validation') == 'failed' or not log.get('file_hash'): + return True + + # Runtime secret mount without approval + if evt == 'runtime_update': + if log.get('secret_provisioned') and not log.get('approval_ticket'): + return True + + # Manifest or provider permission escalation + if evt == 'manifest_update': + if log.get('permission_change') == 'escalation': + return True + + return False + + def test_unauthorized_config_write(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'unauthorized_config_write') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertTrue(result) + self.assertTrue(scenario['expected_detection']) + + def test_provider_endpoint_swap(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'provider_endpoint_swap') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertTrue(result) + self.assertTrue(scenario['expected_detection']) + + def test_runtime_plaintext_secret_mount(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'runtime_plaintext_secret_mount') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertTrue(result) + self.assertTrue(scenario['expected_detection']) + + def test_permission_escalation_manifest(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'permission_escalation_in_manifest') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertTrue(result) + self.assertTrue(scenario['expected_detection']) + + def test_plaintext_secret_in_repo_benign(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'plaintext_secret_in_repo_benign') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertFalse(result) + self.assertFalse(scenario['expected_detection']) + + def test_signed_config_reload_ok_benign(self): + scenario = next(s for s in self.scenarios if s['scenario_id'] == 'signed_config_reload_ok_benign') + result = self.evaluate_detection_rule(scenario['logs']) + self.assertFalse(result) + self.assertFalse(scenario['expected_detection']) + + def test_coverage_detection(self): + detected = 0 + total_malicious = sum(1 for s in self.scenarios if s['expected_detection']) + + for s in self.scenarios: + if s['expected_detection']: + if self.evaluate_detection_rule(s['logs']): + detected += 1 + else: + self.fail(f"Malicious scenario not detected: {s['scenario_id']}") + + self.assertEqual(detected, total_malicious) + + def test_log_format_consistency(self): + required_fields = ["timestamp", "event_type"] + + for scenario in self.scenarios: + for log in scenario['logs']: + for f in required_fields: + self.assertIn(f, log, f"Missing required field {f} in scenario {scenario['scenario_id']}") + + try: + datetime.fromisoformat(log['timestamp'].replace('Z', '+00:00')) + except Exception: + self.fail(f"Invalid timestamp format in scenario {scenario['scenario_id']}: {log['timestamp']}") + + +class TestDetectionPerformance(unittest.TestCase): + def test_detection_performance(self): + large_logs = [] + for _ in range(2000): + large_logs.append({ + 'timestamp': '2025-11-20T14:00:00Z', + 'event_type': 'file_write', + 'file_path': 'mcp_config.json', + 'actor_trust_level': 'approved' + }) + + start = datetime.now() + detected = False + + for l in large_logs: + if l.get('event_type') == 'file_write' and l.get('actor_trust_level') == 'unapproved': + detected = True + break + + duration = (datetime.now() - start).total_seconds() + self.assertLess(duration, 1.0, f"Performance too slow: {duration}s") + + +if __name__ == '__main__': + unittest.main(verbosity=2)