Encrypt sensitive credential fields before event bus emission (#215)

- Add encrypt_credential_dict() and decrypt_credential_field() to utils/crypto.py
- Create utils/credential_encryption.py with encryption/decryption helpers
- Add get_credential_encryption_key() to retrieve key from Infisical at runtime
- Add emit_credential_found() wrapper for modules to use instead of direct bus.emit()
- Update all 15 modules emitting CREDENTIAL_FOUND to use encrypted wrapper
- Update 4 modules consuming CREDENTIAL_FOUND to decrypt payload before processing
- Sensitive fields (username, password, hash, token, etc.) encrypted with AES-256-GCM
- Falls back to plaintext if encryption key unavailable or encryption fails
This commit is contained in:
Cobra
2026-04-06 11:43:46 -04:00
parent f15b8994cd
commit edf2ea7c36
18 changed files with 256 additions and 63 deletions
+9 -8
View File
@@ -22,6 +22,7 @@ from pathlib import Path
from typing import Optional
from modules.base import BaseModule
from utils.credential_encryption import emit_credential_found
logger = logging.getLogger("sensor.passive.db_interceptor")
@@ -286,14 +287,14 @@ class DBInterceptor(BaseModule):
f"LOGIN hostname={hostname} app={appname}", "login"
)
self.bus.emit("CREDENTIAL_FOUND", {
emit_credential_found(self.bus, self.name, {
"source": "mssql_tds_login",
"username": username,
"hostname": hostname,
"source_ip": src_ip,
"dest_ip": dst_ip,
"database": database,
}, source_module=self.name)
})
except Exception:
logger.debug("Failed to parse TDS Login7", exc_info=True)
@@ -423,13 +424,13 @@ class DBInterceptor(BaseModule):
self._stats["logins_captured"] += 1
self._record_query(ts, src_ip, dst_ip, "mysql", username, database, "", "login")
self.bus.emit("CREDENTIAL_FOUND", {
emit_credential_found(self.bus, self.name, {
"source": "mysql_login",
"username": username,
"database": database,
"source_ip": src_ip,
"dest_ip": dst_ip,
}, source_module=self.name)
})
except Exception:
logger.debug("Failed to parse MySQL login", exc_info=True)
@@ -499,13 +500,13 @@ class DBInterceptor(BaseModule):
self._stats["logins_captured"] += 1
self._record_query(ts, src_ip, dst_ip, "postgres", username, database, "", "login")
self.bus.emit("CREDENTIAL_FOUND", {
emit_credential_found(self.bus, self.name, {
"source": "postgres_startup",
"username": username,
"database": database,
"source_ip": src_ip,
"dest_ip": dst_ip,
}, source_module=self.name)
})
# ------------------------------------------------------------------
# Redis parser
@@ -533,12 +534,12 @@ class DBInterceptor(BaseModule):
self._stats["logins_captured"] += 1
self._record_query(ts, src_ip, dst_ip, "redis", username, "", "AUTH ***", "login")
self.bus.emit("CREDENTIAL_FOUND", {
emit_credential_found(self.bus, self.name, {
"source": "redis_auth",
"username": username,
"source_ip": src_ip,
"dest_ip": dst_ip,
}, source_module=self.name)
})
elif cmd in ("GET", "SET", "HGET", "HSET", "DEL", "KEYS",
"MGET", "MSET", "LPUSH", "RPUSH", "SADD", "ZADD"):