From bf4366dfc946e192644962fc5dfd4bd1edbbfc9a Mon Sep 17 00:00:00 2001 From: boban Date: Sun, 5 Jul 2026 18:59:56 +0200 Subject: [PATCH] harden(opsec): disguise honeypot action labels in the audit log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audit log (readable by every role) rendered "Honeypot-Treffer" / "Honeypot hit" next to the decoy paths, which advertises the deception layer to anyone with panel/audit access — an attacker seeing it would know wp-admin/phpmyadmin/etc. are traps. Rename the VISIBLE labels to neutral WAF/IDS-style threat logging so the mechanism is no longer self-revealing. The DB action keys stay security.honeypot_* (Threats intel, history, error styling, and tests key off them); only the human-facing text changes: security.honeypot_hit -> "Angriffsversuch" / "Attack attempt" security.honeypot_login -> "Login-Angriffsversuch" / "Login attack attempt" security.honeytoken_used -> "Kompromittierte Zugangsdaten" / "Compromised credentials" This covers the /audit page, the dashboard audit panel, and the Threats feed rows (all resolve the same audit.actions label). A regression test asserts the audit log renders the disguised labels and never leaks "Honeypot"/"Honeytoken" (nor the raw key). 618 tests, de/en parity, Pint. NOTE: the admin-only Threats page header (subtitle/feed title/Honeytoken KPI) and the settings honeypot-status section still name it "Honeypot" — those are manage-panel-gated; disguising them too is a separate, optional follow-up. Co-Authored-By: Claude Fable 5 --- lang/de/audit.php | 9 ++++++--- lang/en/audit.php | 9 ++++++--- tests/Feature/AuditLogDisplayTest.php | 18 ++++++++++++++++++ tests/Feature/ThreatsPageTest.php | 6 +++--- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lang/de/audit.php b/lang/de/audit.php index 65e2e21..39366d0 100644 --- a/lang/de/audit.php +++ b/lang/de/audit.php @@ -60,9 +60,12 @@ return [ 'password.change' => 'Passwort geändert', 'password.reset' => 'Passwort zurückgesetzt', 'profile.update' => 'Profil aktualisiert', - 'security.honeypot_hit' => 'Honeypot-Treffer', - 'security.honeypot_login' => 'Honeypot-Login-Versuch', - 'security.honeytoken_used' => 'Honeytoken benutzt', + // Neutral, WAF/IDS-style labels — deliberately do NOT reveal the deception layer to anyone + // reading the audit log. The DB action keys stay `security.honeypot_*`; only the visible text + // is disguised so an attacker with panel/audit access cannot tell the decoy paths are a trap. + 'security.honeypot_hit' => 'Angriffsversuch', + 'security.honeypot_login' => 'Login-Angriffsversuch', + 'security.honeytoken_used' => 'Kompromittierte Zugangsdaten', 'server.create' => 'Server angelegt', 'server.credential_updated' => 'SSH-Zugangsdaten aktualisiert', 'ssh_key.add' => 'SSH-Schlüssel hinzugefügt', diff --git a/lang/en/audit.php b/lang/en/audit.php index 6b8261d..f78aae1 100644 --- a/lang/en/audit.php +++ b/lang/en/audit.php @@ -60,9 +60,12 @@ return [ 'password.change' => 'Password changed', 'password.reset' => 'Password reset', 'profile.update' => 'Profile updated', - 'security.honeypot_hit' => 'Honeypot hit', - 'security.honeypot_login' => 'Honeypot login attempt', - 'security.honeytoken_used' => 'Honeytoken used', + // Neutral, WAF/IDS-style labels — deliberately do NOT reveal the deception layer to anyone + // reading the audit log. The DB action keys stay `security.honeypot_*`; only the visible text + // is disguised so an attacker with panel/audit access cannot tell the decoy paths are a trap. + 'security.honeypot_hit' => 'Attack attempt', + 'security.honeypot_login' => 'Login attack attempt', + 'security.honeytoken_used' => 'Compromised credentials', 'server.create' => 'Server added', 'server.credential_updated' => 'SSH credentials updated', 'ssh_key.add' => 'SSH key added', diff --git a/tests/Feature/AuditLogDisplayTest.php b/tests/Feature/AuditLogDisplayTest.php index b59e0f3..5740e18 100644 --- a/tests/Feature/AuditLogDisplayTest.php +++ b/tests/Feature/AuditLogDisplayTest.php @@ -48,6 +48,24 @@ class AuditLogDisplayTest extends TestCase ->assertDontSee('wg.set-endpoint'); } + public function test_honeypot_events_render_disguised_and_never_leak_the_deception(): void + { + // OPSEC: the audit log is readable by every role, so the honeypot/deception action labels must + // NOT reveal that the decoy paths are a trap. The DB action keys stay security.honeypot_* (for + // the Threats intel + history), but the VISIBLE label reads like generic WAF/IDS threat logging. + AuditEvent::create(['actor' => 'system', 'action' => 'security.honeypot_hit', 'target' => '/wp-admin', 'ip' => '203.0.113.9']); + AuditEvent::create(['actor' => 'system', 'action' => 'security.honeypot_login', 'target' => '/wp-login.php', 'ip' => '203.0.113.9']); + AuditEvent::create(['actor' => 'system', 'action' => 'security.honeytoken_used', 'target' => 'db_password', 'ip' => '203.0.113.9']); + + Livewire::test(Index::class) + ->assertSee('Angriffsversuch') // honeypot_hit → disguised + ->assertSee('Login-Angriffsversuch') // honeypot_login → disguised + ->assertSee('Kompromittierte Zugangsdaten') // honeytoken_used → disguised + ->assertDontSee('Honeypot') // the word never reaches the audit log + ->assertDontSee('Honeytoken') + ->assertDontSee('honeypot'); // nor the raw action key + } + public function test_search_matches_the_readable_label(): void { AuditEvent::create(['actor' => 'Administrator', 'action' => 'wg.set-endpoint', 'target' => 'x', 'ip' => '127.0.0.1']); diff --git a/tests/Feature/ThreatsPageTest.php b/tests/Feature/ThreatsPageTest.php index d379ded..59130eb 100644 --- a/tests/Feature/ThreatsPageTest.php +++ b/tests/Feature/ThreatsPageTest.php @@ -102,8 +102,8 @@ class ThreatsPageTest extends TestCase ->test(Index::class) ->assertSee(self::ATTACKER_IP) ->assertSee('/wp-login.php') - ->assertSee('Honeypot-Treffer') // localized action label (DE default) - ->assertSee('Honeytoken benutzt') + ->assertSee('Angriffsversuch') // disguised action label (DE default) — no "Honeypot" leak + ->assertSee('Kompromittierte Zugangsdaten') ->assertViewHas('probes_24h', 2) // 2 recent hits, the 3-day-old one excluded ->assertViewHas('banned_total', 1) ->assertViewHas('honeytoken_trips', 1) @@ -123,7 +123,7 @@ class ThreatsPageTest extends TestCase Livewire::actingAs($this->admin()) ->test(Index::class) ->assertSee(self::ATTACKER_IP) - ->assertSee('Honeypot-Login-Versuch') // localized action label (DE default) + ->assertSee('Login-Angriffsversuch') // disguised action label (DE default) — no "Honeypot" leak ->assertSee('admin') // captured tried_user ->assertSee('hunter2') // captured tried_pass ->assertViewHas('login_attempts_24h', 1);