Skip to content

Commit ee93fc8

Browse files
security: add gitleaks scanning + 2026-04-18 delta review (#403)
* security: add gitleaks scanning + 2026-04-18 security delta review Delta review between PR #377 (2026-03-17) and 7b42e36 found no new critical/high issues. Three cybersecurity-skills toolkits ran: gitleaks secret scanning, GitHub Actions workflow hardening, and cryptographic audit of the delta. Historic leak surfaced: 4 real test-instance tokens (zwqg, plasma, zulu, badger) sat in public git history from late-2025 / early-2026. All four are now dead ('Invalid token' response), so the exposure is stale — but worth documenting and preventing recurrence. Adds: - .gitleaks.toml: custom rules for NetBox v1 (40-hex) and v2 (nbt_*) token formats plus a project-wide allowlist (docker-compose bootstrap token, Slack webhook placeholders, generic 'your-key' patterns) - .gitleaks-baseline.json: snapshot of 8 historic (dead-token) findings so CI only flags new secrets - .github/workflows/secret-scan.yml: gitleaks CI on every push/PR to dev/main via gitleaks-action@v2 - .pre-commit-config.yaml: opt-in local gitleaks pre-commit hook - docs/superpowers/reviews/2026-04-18-security-delta-review.md: full findings report with severity tags and follow-up PR list Medium findings documented for follow-up (not fixed here): - pre-release-validation.yml: 5 \${{ inputs.* }} interpolations into pwsh run-blocks (script injection vector via workflow_dispatch) - actions/* SHA pinning: 25+ unpinned references to GitHub-owned actions (supply-chain hardening) Positive findings worth preserving: - PR #377 HTTP-plaintext warning, SkipCertificateCheck opt-in, AllowInsecureRedirect warning are all intact - zwqg token was protected by NetBox per-token IP allowlist during its live window — a defense-in-depth layer that should be enabled on all prod-hosted tokens - Central auth + TLS code in InvokeNetboxRequest, Connect-NBAPI, Set-NBCipherSSL is unchanged since PR #377 (no regressions) * security: widen gitleaks v1-token rule to catch low-entropy hex The initial rule required a 'netbox_token' / 'api_token' prefix, which missed tokens committed as plain PowerShell 'Token = ''aaaa4bb9...'''. Gitleaks' default generic-api-key uses entropy >= 3.5, but the exposed 'aaaa4bb91eb7...' token scores 3.37 (below threshold) because of the 'aaaa' prefix. Widened the keyword alternation to also match bare 'token' / 'apikey' / 'api_key' as assignment prefixes, which catches the common PowerShell hashtable / YAML / JSON patterns without being so loose that it matches any 40-hex string. Regenerated the baseline to capture the 9 historic findings (previous 8 + the 'aaaa4bb9' in ScenarioTestHelper.psm1 that was missing). Verified: - Synthetic test: 'Token = ''aaaa...''' now flagged - Baseline-suppressed full scan: 'no leaks found' on HEAD * security: address Gemini review — tighten allowlist, drop path exclusions Two of Gemini's three review comments were valid: 1. Bracket-placeholder regex was too broad (HIGH — valid) Previous: `(<|\[|\{)[^>\]\}]*(token|key|secret|password)[^>\]\}]*(>|\]|\})` This silently allowlisted real secrets inside PowerShell hashtables and JSON objects, e.g.: @{ token = 'real_secret_value' } {"secret": "real_value"} The curly-brace match would swallow the entire structure. Fix: narrow to angle-bracket placeholders only, with an enumerated placeholder-prefix word: <(your|placeholder|example|fake|insert|my)?[-_]?(api[-_]?)?(token|key|secret|password|pat)> Still matches <YOUR_TOKEN>, <MY_API_KEY>, <PAT>, <TOKEN>. Does NOT match @{ token = '...' } or {"secret": "..."} — real secrets in those contexts are now correctly flagged. 2. Tests/ and docs/ path exclusions dropped (MEDIUM — valid) Gemini: "Real tokens have landed in tests before" — and indeed, the very tokens this PR documents leaked via Tests/Scenario/ScenarioTestHelper.psm1. Keeping these paths scannable catches that class of mistake again. Added 'nbt_abc123def456.ghijklmnopqrstuvwxyz1234567890' (the one placeholder token in Tests/Setup.Tests.ps1) to the v2-token rule allowlist. No other Tests/ or docs/ entries triggered findings with the existing allowlist — no ongoing maintenance burden. The third comment (v8.30.1 doesn't exist) was empirically refuted — `curl https://api.github.com/repos/gitleaks/gitleaks/releases` returns v8.30.1 as the current latest (published 2026-03-21). Gemini's training data apparently predates the v8.22+ release line. Pinned version is correct; see the pre-commit-hooks.io mirror for confirmation. Baseline regenerated: 10 entries (was 9) — added the one Tests/Setup.Tests.ps1 placeholder that the path exclusion previously hid. * security: round 2 Gemini feedback — word boundaries + global placeholders Addresses Gemini's second-round review (2026-04-18T09:00:46Z): 1. Added \b word boundaries to netbox-v2-token regex (valid, MEDIUM) Prevents partial matches within larger alphanumeric strings. 2. Moved v2 token placeholders from [rules.allowlist] to global [allowlist].regexes (valid, MEDIUM). Now suppressed against every rule including the default generic-api-key rule. 3. v1 token rule hardening (partially valid, MEDIUM): - Added \b boundaries so exactly 40 hex chars are required (a 48-hex string won't match the first 40 — precisely what Gemini's (?![a-f0-9]) lookahead would have achieved, but Go's regexp package doesn't support lookahead, so \b is the portable equivalent — verified empirically: gitleaks panics on Perl-syntax `(?!`) - Added "api-key" (dash form) to keywords for broader trigger - Added secretGroup = 1 so fingerprint uses the captured token value, not the full match including the keyword prefix Baseline regenerated: 9 entries (was 10 — the tightened v2 rule no longer flags the nbt_abc123def456.ghijklmnopqrstuvwxyz1234567890 placeholder since it's now globally allowlisted). Synthetic verification: - 'Token = ''aaaa4bb9...40hex''': flagged ✓ - 'nbt_kVJSfSxl3xvO.b4K...': flagged ✓ - nbt_abc123def456.ghijk... placeholder: suppressed ✓ - @{ secret = 'abc...42hex' } (real-looking secret in hashtable): now flagged by default generic-api-key (the overly-broad bracket allowlist from v1 no longer hides it) ✓ * security: add leading \b to v1 token rule (round 3 Gemini) Without a leading word boundary, the v1 token regex would partial-match the substring 'Token' inside identifiers like PowerShell's `$CancellationToken` or .NET's `CancellationToken`, producing false positives on any 40-hex value assigned to such a variable. Verified empirically: $CancellationToken = '<40-hex>' Before: flagged by netbox-v1-token rule (FP) After: flagged only by generic-api-key entropy rule (correct default gitleaks behavior; my custom rule now correctly abstains) `$Token = '<40-hex>'` still flagged by netbox-v1-token (intended). Baseline unchanged at 9 entries — all historic findings use `Token =` or equivalent identifiers that already start at a word boundary.
1 parent 7b42e36 commit ee93fc8

5 files changed

Lines changed: 630 additions & 0 deletions

File tree

.github/workflows/secret-scan.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Secret Scan
2+
3+
on:
4+
push:
5+
branches: [dev, main, master]
6+
pull_request:
7+
branches: [dev, main, master]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
gitleaks:
14+
name: Gitleaks
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0 # Full history — gitleaks needs commits to scan
21+
22+
- name: Run gitleaks
23+
uses: gitleaks/gitleaks-action@v2
24+
env:
25+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
# Gitleaks picks up .gitleaks.toml and .gitleaks-baseline.json
27+
# from the repo root automatically.
28+
GITLEAKS_ENABLE_SUMMARY: "true"
29+
GITLEAKS_ENABLE_COMMENTS: "true"

.gitleaks-baseline.json

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
[
2+
{
3+
"RuleID": "netbox-v2-token",
4+
"Description": "NetBox v2 Bearer token (nbt_\u003ckey\u003e.\u003csecret\u003e)",
5+
"StartLine": 272,
6+
"EndLine": 272,
7+
"StartColumn": 23,
8+
"EndColumn": 79,
9+
"Match": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
10+
"Secret": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
11+
"File": ".github/workflows/integration.yml",
12+
"SymlinkFile": "",
13+
"Commit": "8044791c23a49df78e385aca6ffc74b0023f8ab1",
14+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/8044791c23a49df78e385aca6ffc74b0023f8ab1/.github/workflows/integration.yml#L272",
15+
"Entropy": 5.043073,
16+
"Author": "ctrl-alt-automate",
17+
"Email": "elvis@deployment-team.nl",
18+
"Date": "2026-01-06T12:54:06Z",
19+
"Message": "security: Remove hardcoded tokens from ScenarioTestHelper\n\nBREAKING CHANGE: Test credentials now loaded from environment variables\n\nRequired environment variables:\n- NETBOX_449_HOST / NETBOX_449_TOKEN (plasma-paint)\n- NETBOX_449_ZWQG_HOST / NETBOX_449_ZWQG_TOKEN (cloud.netboxapp.com)\n- NETBOX_437_HOST / NETBOX_437_TOKEN (badger-victor)\n- NETBOX_450_HOST / NETBOX_450_TOKEN (zulu-how)\n\nAdded validation with clear error messages when env vars are missing.\n\nIMPORTANT: Revoke and regenerate all exposed tokens immediately!\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
20+
"Tags": [
21+
"netbox",
22+
"token",
23+
"v2"
24+
],
25+
"Fingerprint": "8044791c23a49df78e385aca6ffc74b0023f8ab1:.github/workflows/integration.yml:netbox-v2-token:272"
26+
},
27+
{
28+
"RuleID": "netbox-v2-token",
29+
"Description": "NetBox v2 Bearer token (nbt_\u003ckey\u003e.\u003csecret\u003e)",
30+
"StartLine": 28,
31+
"EndLine": 28,
32+
"StartColumn": 22,
33+
"EndColumn": 78,
34+
"Match": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
35+
"Secret": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
36+
"File": "Tests/Scenario/ScenarioTestHelper.psm1",
37+
"SymlinkFile": "",
38+
"Commit": "02c3b9594f380b310bc07ea43487019d3d960e49",
39+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/02c3b9594f380b310bc07ea43487019d3d960e49/Tests/Scenario/ScenarioTestHelper.psm1#L28",
40+
"Entropy": 5.043073,
41+
"Author": "ctrl-alt-automate",
42+
"Email": "elvis@deployment-team.nl",
43+
"Date": "2026-01-03T15:16:15Z",
44+
"Message": "feat: Add 500 error fallback for bulk operations\n\nWhen bulk API requests fail with 500 Internal Server Error (which can\noccur due to Redis cache inconsistency on cloud-hosted Netbox instances),\nthe module now automatically falls back to sequential single-item requests.\n\nChanges:\n- Send-NBBulkRequest: Add 500 error detection and sequential fallback\n with exponential backoff retry (3 attempts, 500ms/1s/2s delays)\n- Connect-NBAPI: Add AllowInsecureRedirect for PS 7.4+ compatibility\n- Set-NBIPAMAddress: Add ValueFromPipelineByPropertyName to Status/Description\n- Get-NBTenant: Rename GroupID to Group_Id with backwards-compatible alias\n- Add Scenario test suite for bulk operations, workflows, filters\n\nFixes: Test file bug where $($i++) in string interpolation doesn't work\nin PowerShell - increment must be on separate line before use.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
45+
"Tags": [
46+
"netbox",
47+
"token",
48+
"v2"
49+
],
50+
"Fingerprint": "02c3b9594f380b310bc07ea43487019d3d960e49:Tests/Scenario/ScenarioTestHelper.psm1:netbox-v2-token:28"
51+
},
52+
{
53+
"RuleID": "netbox-v1-token",
54+
"Description": "NetBox v1 API token (40-char hex key)",
55+
"StartLine": 13,
56+
"EndLine": 13,
57+
"StartColumn": 10,
58+
"EndColumn": 62,
59+
"Match": "Token = '4188039a3a05ebb58e4969873bace61c77222eb7'",
60+
"Secret": "4188039a3a05ebb58e4969873bace61c77222eb7",
61+
"File": "Tests/Scenario/ScenarioTestHelper.psm1",
62+
"SymlinkFile": "",
63+
"Commit": "02c3b9594f380b310bc07ea43487019d3d960e49",
64+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/02c3b9594f380b310bc07ea43487019d3d960e49/Tests/Scenario/ScenarioTestHelper.psm1#L13",
65+
"Entropy": 3.7464395,
66+
"Author": "ctrl-alt-automate",
67+
"Email": "elvis@deployment-team.nl",
68+
"Date": "2026-01-03T15:16:15Z",
69+
"Message": "feat: Add 500 error fallback for bulk operations\n\nWhen bulk API requests fail with 500 Internal Server Error (which can\noccur due to Redis cache inconsistency on cloud-hosted Netbox instances),\nthe module now automatically falls back to sequential single-item requests.\n\nChanges:\n- Send-NBBulkRequest: Add 500 error detection and sequential fallback\n with exponential backoff retry (3 attempts, 500ms/1s/2s delays)\n- Connect-NBAPI: Add AllowInsecureRedirect for PS 7.4+ compatibility\n- Set-NBIPAMAddress: Add ValueFromPipelineByPropertyName to Status/Description\n- Get-NBTenant: Rename GroupID to Group_Id with backwards-compatible alias\n- Add Scenario test suite for bulk operations, workflows, filters\n\nFixes: Test file bug where $($i++) in string interpolation doesn't work\nin PowerShell - increment must be on separate line before use.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
70+
"Tags": [
71+
"netbox",
72+
"token",
73+
"v1"
74+
],
75+
"Fingerprint": "02c3b9594f380b310bc07ea43487019d3d960e49:Tests/Scenario/ScenarioTestHelper.psm1:netbox-v1-token:13"
76+
},
77+
{
78+
"RuleID": "netbox-v1-token",
79+
"Description": "NetBox v1 API token (40-char hex key)",
80+
"StartLine": 18,
81+
"EndLine": 18,
82+
"StartColumn": 10,
83+
"EndColumn": 62,
84+
"Match": "Token = 'a9717b9520d54d19383649066ef3b25e313bf219'",
85+
"Secret": "a9717b9520d54d19383649066ef3b25e313bf219",
86+
"File": "Tests/Scenario/ScenarioTestHelper.psm1",
87+
"SymlinkFile": "",
88+
"Commit": "02c3b9594f380b310bc07ea43487019d3d960e49",
89+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/02c3b9594f380b310bc07ea43487019d3d960e49/Tests/Scenario/ScenarioTestHelper.psm1#L18",
90+
"Entropy": 3.7659574,
91+
"Author": "ctrl-alt-automate",
92+
"Email": "elvis@deployment-team.nl",
93+
"Date": "2026-01-03T15:16:15Z",
94+
"Message": "feat: Add 500 error fallback for bulk operations\n\nWhen bulk API requests fail with 500 Internal Server Error (which can\noccur due to Redis cache inconsistency on cloud-hosted Netbox instances),\nthe module now automatically falls back to sequential single-item requests.\n\nChanges:\n- Send-NBBulkRequest: Add 500 error detection and sequential fallback\n with exponential backoff retry (3 attempts, 500ms/1s/2s delays)\n- Connect-NBAPI: Add AllowInsecureRedirect for PS 7.4+ compatibility\n- Set-NBIPAMAddress: Add ValueFromPipelineByPropertyName to Status/Description\n- Get-NBTenant: Rename GroupID to Group_Id with backwards-compatible alias\n- Add Scenario test suite for bulk operations, workflows, filters\n\nFixes: Test file bug where $($i++) in string interpolation doesn't work\nin PowerShell - increment must be on separate line before use.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
95+
"Tags": [
96+
"netbox",
97+
"token",
98+
"v1"
99+
],
100+
"Fingerprint": "02c3b9594f380b310bc07ea43487019d3d960e49:Tests/Scenario/ScenarioTestHelper.psm1:netbox-v1-token:18"
101+
},
102+
{
103+
"RuleID": "netbox-v1-token",
104+
"Description": "NetBox v1 API token (40-char hex key)",
105+
"StartLine": 23,
106+
"EndLine": 23,
107+
"StartColumn": 10,
108+
"EndColumn": 62,
109+
"Match": "Token = 'aaaa4bb91eb74fe02ec1be9a83940341a49b1e9a'",
110+
"Secret": "aaaa4bb91eb74fe02ec1be9a83940341a49b1e9a",
111+
"File": "Tests/Scenario/ScenarioTestHelper.psm1",
112+
"SymlinkFile": "",
113+
"Commit": "02c3b9594f380b310bc07ea43487019d3d960e49",
114+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/02c3b9594f380b310bc07ea43487019d3d960e49/Tests/Scenario/ScenarioTestHelper.psm1#L23",
115+
"Entropy": 3.3696768,
116+
"Author": "ctrl-alt-automate",
117+
"Email": "elvis@deployment-team.nl",
118+
"Date": "2026-01-03T15:16:15Z",
119+
"Message": "feat: Add 500 error fallback for bulk operations\n\nWhen bulk API requests fail with 500 Internal Server Error (which can\noccur due to Redis cache inconsistency on cloud-hosted Netbox instances),\nthe module now automatically falls back to sequential single-item requests.\n\nChanges:\n- Send-NBBulkRequest: Add 500 error detection and sequential fallback\n with exponential backoff retry (3 attempts, 500ms/1s/2s delays)\n- Connect-NBAPI: Add AllowInsecureRedirect for PS 7.4+ compatibility\n- Set-NBIPAMAddress: Add ValueFromPipelineByPropertyName to Status/Description\n- Get-NBTenant: Rename GroupID to Group_Id with backwards-compatible alias\n- Add Scenario test suite for bulk operations, workflows, filters\n\nFixes: Test file bug where $($i++) in string interpolation doesn't work\nin PowerShell - increment must be on separate line before use.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
120+
"Tags": [
121+
"netbox",
122+
"token",
123+
"v1"
124+
],
125+
"Fingerprint": "02c3b9594f380b310bc07ea43487019d3d960e49:Tests/Scenario/ScenarioTestHelper.psm1:netbox-v1-token:23"
126+
},
127+
{
128+
"RuleID": "netbox-v2-token",
129+
"Description": "NetBox v2 Bearer token (nbt_\u003ckey\u003e.\u003csecret\u003e)",
130+
"StartLine": 242,
131+
"EndLine": 242,
132+
"StartColumn": 24,
133+
"EndColumn": 80,
134+
"Match": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
135+
"Secret": "nbt_kVJSfSxl3xvO.b4KIab8fc0sKntsws0KK7j6VwWNYnztZ9BOC7NAq",
136+
"File": ".github/workflows/integration.yml",
137+
"SymlinkFile": "",
138+
"Commit": "a449cfaa9c6c7618986285ab852df27a9e863c0b",
139+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/a449cfaa9c6c7618986285ab852df27a9e863c0b/.github/workflows/integration.yml#L242",
140+
"Entropy": 5.043073,
141+
"Author": "ctrl-alt-automate",
142+
"Email": "elvis@deployment-team.nl",
143+
"Date": "2025-12-30T09:13:28Z",
144+
"Message": "ci: Add exe.dev live testing workflow and v2 token support\n\n- Update version matrix: 4.3.7, 4.4.9, 4.5.0-beta1\n- Add v2 token tests for Netbox 4.5+ in integration.yml\n- Add 4.5.0-beta1 to compatibility.yml\n- Create exe-dev-tests.yml for testing against live exe.dev VMs\n - Manual trigger with VM selection (all/stable/minimum/beta)\n - Quick and full test scopes\n - Requires EXEDEV_TOKEN_* secrets\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
145+
"Tags": [
146+
"netbox",
147+
"token",
148+
"v2"
149+
],
150+
"Fingerprint": "a449cfaa9c6c7618986285ab852df27a9e863c0b:.github/workflows/integration.yml:netbox-v2-token:242"
151+
},
152+
{
153+
"RuleID": "netbox-v1-token",
154+
"Description": "NetBox v1 API token (40-char hex key)",
155+
"StartLine": 21,
156+
"EndLine": 21,
157+
"StartColumn": 2,
158+
"EndColumn": 49,
159+
"Match": "TOKEN=\"a9717b9520d54d19383649066ef3b25e313bf219\"",
160+
"Secret": "a9717b9520d54d19383649066ef3b25e313bf219",
161+
"File": ".claude/commands/netbox-api.md",
162+
"SymlinkFile": "",
163+
"Commit": "ef1726d42f622dedf4579016dd6a4fa13df26f17",
164+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/ef1726d42f622dedf4579016dd6a4fa13df26f17/.claude/commands/netbox-api.md?plain=1#L21",
165+
"Entropy": 3.7659574,
166+
"Author": "ctrl-alt-automate",
167+
"Email": "elvis@deployment-team.nl",
168+
"Date": "2025-12-10T22:15:53Z",
169+
"Message": "Add development tooling and Claude Code integration\n\n- Add CLAUDE.md with project overview and development guide\n- Add Connect-DevNetbox.ps1 helper script for quick API connection\n- Add .netboxps.config.example.ps1 template for local credentials\n- Add specialized slash commands for AI-assisted development:\n - /netbox-api: Netbox API expert for endpoint documentation\n - /powershell-expert: PowerShell best practices guidance\n - /implement: Combined workflow for new endpoint implementation\n - /test-endpoint: Compatibility testing against Netbox 4.4.7\n- Update .gitignore to exclude local config files\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
170+
"Tags": [
171+
"netbox",
172+
"token",
173+
"v1"
174+
],
175+
"Fingerprint": "ef1726d42f622dedf4579016dd6a4fa13df26f17:.claude/commands/netbox-api.md:netbox-v1-token:21"
176+
},
177+
{
178+
"RuleID": "netbox-v1-token",
179+
"Description": "NetBox v1 API token (40-char hex key)",
180+
"StartLine": 8,
181+
"EndLine": 8,
182+
"StartColumn": 2,
183+
"EndColumn": 49,
184+
"Match": "TOKEN=\"a9717b9520d54d19383649066ef3b25e313bf219\"",
185+
"Secret": "a9717b9520d54d19383649066ef3b25e313bf219",
186+
"File": ".claude/commands/test-endpoint.md",
187+
"SymlinkFile": "",
188+
"Commit": "ef1726d42f622dedf4579016dd6a4fa13df26f17",
189+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/ef1726d42f622dedf4579016dd6a4fa13df26f17/.claude/commands/test-endpoint.md?plain=1#L8",
190+
"Entropy": 3.7659574,
191+
"Author": "ctrl-alt-automate",
192+
"Email": "elvis@deployment-team.nl",
193+
"Date": "2025-12-10T22:15:53Z",
194+
"Message": "Add development tooling and Claude Code integration\n\n- Add CLAUDE.md with project overview and development guide\n- Add Connect-DevNetbox.ps1 helper script for quick API connection\n- Add .netboxps.config.example.ps1 template for local credentials\n- Add specialized slash commands for AI-assisted development:\n - /netbox-api: Netbox API expert for endpoint documentation\n - /powershell-expert: PowerShell best practices guidance\n - /implement: Combined workflow for new endpoint implementation\n - /test-endpoint: Compatibility testing against Netbox 4.4.7\n- Update .gitignore to exclude local config files\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
195+
"Tags": [
196+
"netbox",
197+
"token",
198+
"v1"
199+
],
200+
"Fingerprint": "ef1726d42f622dedf4579016dd6a4fa13df26f17:.claude/commands/test-endpoint.md:netbox-v1-token:8"
201+
},
202+
{
203+
"RuleID": "netbox-v1-token",
204+
"Description": "NetBox v1 API token (40-char hex key)",
205+
"StartLine": 12,
206+
"EndLine": 12,
207+
"StartColumn": 2,
208+
"EndColumn": 49,
209+
"Match": "TOKEN=\"a9717b9520d54d19383649066ef3b25e313bf219\"",
210+
"Secret": "a9717b9520d54d19383649066ef3b25e313bf219",
211+
"File": ".claude/commands/implement.md",
212+
"SymlinkFile": "",
213+
"Commit": "ef1726d42f622dedf4579016dd6a4fa13df26f17",
214+
"Link": "https://github.com/ctrl-alt-automate/PowerNetbox/blob/ef1726d42f622dedf4579016dd6a4fa13df26f17/.claude/commands/implement.md?plain=1#L12",
215+
"Entropy": 3.7659574,
216+
"Author": "ctrl-alt-automate",
217+
"Email": "elvis@deployment-team.nl",
218+
"Date": "2025-12-10T22:15:53Z",
219+
"Message": "Add development tooling and Claude Code integration\n\n- Add CLAUDE.md with project overview and development guide\n- Add Connect-DevNetbox.ps1 helper script for quick API connection\n- Add .netboxps.config.example.ps1 template for local credentials\n- Add specialized slash commands for AI-assisted development:\n - /netbox-api: Netbox API expert for endpoint documentation\n - /powershell-expert: PowerShell best practices guidance\n - /implement: Combined workflow for new endpoint implementation\n - /test-endpoint: Compatibility testing against Netbox 4.4.7\n- Update .gitignore to exclude local config files\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \u003cnoreply@anthropic.com\u003e",
220+
"Tags": [
221+
"netbox",
222+
"token",
223+
"v1"
224+
],
225+
"Fingerprint": "ef1726d42f622dedf4579016dd6a4fa13df26f17:.claude/commands/implement.md:netbox-v1-token:12"
226+
}
227+
]

.gitleaks.toml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# PowerNetbox Gitleaks Configuration
2+
# Extends the default rule set with PowerNetbox-specific patterns
3+
# and an allowlist for known test/placeholder values.
4+
5+
title = "PowerNetbox Gitleaks Configuration"
6+
7+
[extend]
8+
useDefault = true
9+
10+
# Custom rule: NetBox v2 Bearer token format (nbt_<key>.<secret>).
11+
# Word boundaries (\b) prevent partial matches inside longer alphanumeric
12+
# strings — e.g. `XnbtX_abc123.xyz...` (unlikely but possible) won't false-
13+
# positive at the inner "nbt_" position.
14+
[[rules]]
15+
id = "netbox-v2-token"
16+
description = "NetBox v2 Bearer token (nbt_<key>.<secret>)"
17+
regex = '''\bnbt_[A-Za-z0-9]{10,}\.[A-Za-z0-9]{30,}\b'''
18+
keywords = ["nbt_"]
19+
tags = ["netbox", "token", "v2"]
20+
21+
# Custom rule: NetBox v1 token (40-char hex). Matches PowerShell assignment
22+
# style (`Token = '...'`), YAML/JSON style (`token: "..."`), and common
23+
# variable-name prefixes (NETBOX_TOKEN, API_TOKEN, etc.).
24+
# This rule catches tokens that gitleaks' built-in generic-api-key rule
25+
# may miss due to low-entropy leading chars (e.g. 'aaaa4bb9...').
26+
# Word boundaries ensure exactly-40-hex match — a 48-hex string won't
27+
# match the first 40 chars. Go's regexp package doesn't support negative
28+
# lookahead, so `\b` is the portable equivalent.
29+
[[rules]]
30+
id = "netbox-v1-token"
31+
description = "NetBox v1 API token (40-char hex key)"
32+
regex = '''(?i)\b(?:token|netbox[_-]?token|nb[_-]?token|api[_-]?token|api[_-]?key)\s*[:=]\s*["']?\b([a-f0-9]{40})\b["']?'''
33+
keywords = ["token", "apikey", "api_key", "api-key"]
34+
secretGroup = 1
35+
tags = ["netbox", "token", "v1"]
36+
37+
# Global allowlist for common PowerNetbox test/placeholder values.
38+
# Placeholders live here (not per-rule) so they're suppressed against every
39+
# rule, including the default generic-api-key entropy scan.
40+
[allowlist]
41+
description = "PowerNetbox project-wide allowlist"
42+
43+
paths = [
44+
# The config file itself contains example patterns that would trip its own rules.
45+
'''(^|/)\.gitleaks\.toml$''',
46+
# Baseline captures historic findings that have been rotated.
47+
'''(^|/)\.gitleaks-baseline\.json$''',
48+
# Note: Tests/ and docs/ are intentionally NOT excluded so real tokens
49+
# accidentally landing there are still caught. Rely on the regex
50+
# allowlist below for known-safe placeholders.
51+
]
52+
53+
regexes = [
54+
# docker-compose.ci.yml bootstrap token (public netbox-docker default)
55+
'''0123456789abcdef0123456789abcdef01234567''',
56+
# Slack webhook placeholder pattern (T00000000/B00000000/XXX...)
57+
'''hooks\.slack\.com/services/T0+/B0+/X+''',
58+
# Common placeholder patterns — matches YOUR_TOKEN, my-api-key, etc.
59+
'''(?i)your[-_]?(api[-_]?)?(token|key|secret)''',
60+
'''(?i)(example|sample|placeholder|fake|dummy|test|insert|my)[-_]?(api[-_]?)?(token|key|secret|password)''',
61+
# NetBox v2 token placeholders used in docs and tests. Kept here (not in
62+
# a per-rule allowlist) so they're also ignored by the generic-api-key
63+
# rule if its entropy heuristic ever catches them.
64+
'''nbt_abc123\.xyz789''',
65+
'''nbt_abc123def456\.ghijklmnopqrstuvwxyz1234567890''',
66+
'''nbt_ExampleKey123\.ExampleSecretValue456789''',
67+
'''nbt_yourKey\.yourSecret''',
68+
'''nbt_\{key\}\.\{secret\}''',
69+
# Angle-bracket placeholders only: <TOKEN>, <YOUR_API_KEY>.
70+
# Intentionally narrow — does NOT match PowerShell hashtables (`@{ token = 'x' }`)
71+
# or JSON objects (`{"secret": "value"}`), which could hide real secrets.
72+
'''(?i)<(your|placeholder|example|fake|insert|my)?[-_]?(api[-_]?)?(token|key|secret|password|pat)>''',
73+
# xxxxxxxx, ****, 00000000 sequences
74+
'''x{8,}''',
75+
'''\*{8,}''',
76+
'''0{10,}''',
77+
]

0 commit comments

Comments
 (0)