@pan-sec/notebooklm-mcp 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/SECURITY.md +539 -0
- package/dist/auth/auth-manager.d.ts +137 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +984 -0
- package/dist/auth/auth-manager.js.map +1 -0
- package/dist/auth/mcp-auth.d.ts +102 -0
- package/dist/auth/mcp-auth.d.ts.map +1 -0
- package/dist/auth/mcp-auth.js +286 -0
- package/dist/auth/mcp-auth.js.map +1 -0
- package/dist/config.d.ts +89 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +216 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/library/notebook-library.d.ts +70 -0
- package/dist/library/notebook-library.d.ts.map +1 -0
- package/dist/library/notebook-library.js +279 -0
- package/dist/library/notebook-library.js.map +1 -0
- package/dist/library/types.d.ts +67 -0
- package/dist/library/types.d.ts.map +1 -0
- package/dist/library/types.js +8 -0
- package/dist/library/types.js.map +1 -0
- package/dist/resources/resource-handlers.d.ts +22 -0
- package/dist/resources/resource-handlers.d.ts.map +1 -0
- package/dist/resources/resource-handlers.js +216 -0
- package/dist/resources/resource-handlers.js.map +1 -0
- package/dist/session/browser-session.d.ts +108 -0
- package/dist/session/browser-session.d.ts.map +1 -0
- package/dist/session/browser-session.js +621 -0
- package/dist/session/browser-session.js.map +1 -0
- package/dist/session/session-manager.d.ts +77 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +314 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/session-timeout.d.ts +122 -0
- package/dist/session/session-timeout.d.ts.map +1 -0
- package/dist/session/session-timeout.js +281 -0
- package/dist/session/session-timeout.js.map +1 -0
- package/dist/session/shared-context-manager.d.ts +107 -0
- package/dist/session/shared-context-manager.d.ts.map +1 -0
- package/dist/session/shared-context-manager.js +447 -0
- package/dist/session/shared-context-manager.js.map +1 -0
- package/dist/tools/definitions/ask-question.d.ts +8 -0
- package/dist/tools/definitions/ask-question.d.ts.map +1 -0
- package/dist/tools/definitions/ask-question.js +211 -0
- package/dist/tools/definitions/ask-question.js.map +1 -0
- package/dist/tools/definitions/notebook-management.d.ts +3 -0
- package/dist/tools/definitions/notebook-management.d.ts.map +1 -0
- package/dist/tools/definitions/notebook-management.js +243 -0
- package/dist/tools/definitions/notebook-management.js.map +1 -0
- package/dist/tools/definitions/session-management.d.ts +3 -0
- package/dist/tools/definitions/session-management.d.ts.map +1 -0
- package/dist/tools/definitions/session-management.js +41 -0
- package/dist/tools/definitions/session-management.js.map +1 -0
- package/dist/tools/definitions/system.d.ts +3 -0
- package/dist/tools/definitions/system.d.ts.map +1 -0
- package/dist/tools/definitions/system.js +143 -0
- package/dist/tools/definitions/system.js.map +1 -0
- package/dist/tools/definitions.d.ts +12 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +26 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers.d.ts +213 -0
- package/dist/tools/handlers.d.ts.map +1 -0
- package/dist/tools/handlers.js +813 -0
- package/dist/tools/handlers.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/audit-logger.d.ts +140 -0
- package/dist/utils/audit-logger.d.ts.map +1 -0
- package/dist/utils/audit-logger.js +361 -0
- package/dist/utils/audit-logger.js.map +1 -0
- package/dist/utils/cert-pinning.d.ts +97 -0
- package/dist/utils/cert-pinning.d.ts.map +1 -0
- package/dist/utils/cert-pinning.js +328 -0
- package/dist/utils/cert-pinning.js.map +1 -0
- package/dist/utils/cleanup-manager.d.ts +133 -0
- package/dist/utils/cleanup-manager.d.ts.map +1 -0
- package/dist/utils/cleanup-manager.js +673 -0
- package/dist/utils/cleanup-manager.js.map +1 -0
- package/dist/utils/cli-handler.d.ts +16 -0
- package/dist/utils/cli-handler.d.ts.map +1 -0
- package/dist/utils/cli-handler.js +102 -0
- package/dist/utils/cli-handler.js.map +1 -0
- package/dist/utils/crypto.d.ts +175 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +612 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/logger.d.ts +61 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +92 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/page-utils.d.ts +54 -0
- package/dist/utils/page-utils.d.ts.map +1 -0
- package/dist/utils/page-utils.js +405 -0
- package/dist/utils/page-utils.js.map +1 -0
- package/dist/utils/response-validator.d.ts +98 -0
- package/dist/utils/response-validator.d.ts.map +1 -0
- package/dist/utils/response-validator.js +352 -0
- package/dist/utils/response-validator.js.map +1 -0
- package/dist/utils/secrets-scanner.d.ts +126 -0
- package/dist/utils/secrets-scanner.d.ts.map +1 -0
- package/dist/utils/secrets-scanner.js +443 -0
- package/dist/utils/secrets-scanner.js.map +1 -0
- package/dist/utils/secure-memory.d.ts +130 -0
- package/dist/utils/secure-memory.d.ts.map +1 -0
- package/dist/utils/secure-memory.js +279 -0
- package/dist/utils/secure-memory.js.map +1 -0
- package/dist/utils/security.d.ts +83 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +272 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/settings-manager.d.ts +37 -0
- package/dist/utils/settings-manager.d.ts.map +1 -0
- package/dist/utils/settings-manager.js +125 -0
- package/dist/utils/settings-manager.js.map +1 -0
- package/dist/utils/stealth-utils.d.ts +135 -0
- package/dist/utils/stealth-utils.d.ts.map +1 -0
- package/dist/utils/stealth-utils.js +398 -0
- package/dist/utils/stealth-utils.js.map +1 -0
- package/dist/utils/tool-validation.d.ts +93 -0
- package/dist/utils/tool-validation.d.ts.map +1 -0
- package/dist/utils/tool-validation.js +277 -0
- package/dist/utils/tool-validation.js.map +1 -0
- package/docs/SECURITY_IMPLEMENTATION_PLAN.md +437 -0
- package/docs/configuration.md +94 -0
- package/docs/tools.md +34 -0
- package/docs/troubleshooting.md +59 -0
- package/docs/usage-guide.md +245 -0
- package/package.json +82 -0
package/SECURITY.md
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# Security Hardening Documentation
|
|
2
|
+
|
|
3
|
+
This is a security-hardened fork of [PleasePrompto/notebooklm-mcp](https://github.com/PleasePrompto/notebooklm-mcp), maintained by [Pantheon Security](https://pantheonsecurity.io).
|
|
4
|
+
|
|
5
|
+
**Version**: 1.4.0-secure
|
|
6
|
+
**Security Features**: 14 hardening layers
|
|
7
|
+
|
|
8
|
+
## Security Features Overview
|
|
9
|
+
|
|
10
|
+
| Feature | Status | Description |
|
|
11
|
+
|---------|--------|-------------|
|
|
12
|
+
| Input Validation | ✅ | URL whitelisting, sanitization |
|
|
13
|
+
| Rate Limiting | ✅ | Per-session request throttling |
|
|
14
|
+
| Log Sanitization | ✅ | Credential masking |
|
|
15
|
+
| Audit Logging | ✅ | Tamper-evident event logging |
|
|
16
|
+
| Session Timeout | ✅ | Hard lifetime + inactivity limits |
|
|
17
|
+
| MCP Authentication | ✅ | Token-based auth with lockout |
|
|
18
|
+
| Response Validation | ✅ | Prompt injection detection |
|
|
19
|
+
| **Post-Quantum Encryption** | ✅ | ML-KEM-768 + ChaCha20-Poly1305 |
|
|
20
|
+
| **Secrets Scanning** | ✅ | Detect API keys, tokens, passwords |
|
|
21
|
+
| **Certificate Pinning** | ✅ | Google TLS MITM protection |
|
|
22
|
+
| **Memory Scrubbing** | ✅ | Zero sensitive data after use |
|
|
23
|
+
| **MEDUSA Integration** | ✅ | Automated security scanning |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Post-Quantum Encryption (NEW)
|
|
28
|
+
|
|
29
|
+
### Why Post-Quantum?
|
|
30
|
+
|
|
31
|
+
Recent events (including alleged quantum computer attacks on major infrastructure) highlight the urgency of preparing for "Q-Day" - when quantum computers can break classical encryption.
|
|
32
|
+
|
|
33
|
+
This MCP uses **hybrid post-quantum encryption** that combines:
|
|
34
|
+
- **ML-KEM-768 (Kyber)** - NIST-standardized post-quantum key encapsulation
|
|
35
|
+
- **ChaCha20-Poly1305** - Modern stream cipher (NOT AES-GCM)
|
|
36
|
+
|
|
37
|
+
### Why ChaCha20-Poly1305 over AES-GCM?
|
|
38
|
+
|
|
39
|
+
| Property | ChaCha20-Poly1305 | AES-GCM |
|
|
40
|
+
|----------|-------------------|---------|
|
|
41
|
+
| Timing attacks | Immune (constant-time) | Vulnerable without AES-NI |
|
|
42
|
+
| Software speed | Fast everywhere | Slow without hardware |
|
|
43
|
+
| Complexity | Simple | Complex (GCM mode) |
|
|
44
|
+
| Adoption | Google, Cloudflare TLS | Legacy systems |
|
|
45
|
+
|
|
46
|
+
This provides **double protection**: even if one algorithm is broken, the other remains secure.
|
|
47
|
+
|
|
48
|
+
### What's Encrypted
|
|
49
|
+
|
|
50
|
+
- Browser session state (cookies, localStorage)
|
|
51
|
+
- Session storage data
|
|
52
|
+
- Post-quantum key pairs (double-encrypted)
|
|
53
|
+
|
|
54
|
+
### Encrypted File Format
|
|
55
|
+
|
|
56
|
+
Files are saved with `.pqenc` extension:
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"version": 3,
|
|
60
|
+
"algorithm": "chacha20-poly1305",
|
|
61
|
+
"pqAlgorithm": "ML-KEM-768",
|
|
62
|
+
"encapsulatedKey": "<base64>",
|
|
63
|
+
"nonce": "<base64>",
|
|
64
|
+
"salt": "<base64>",
|
|
65
|
+
"ciphertext": "<base64 with Poly1305 tag appended>"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Configuration
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Enable/disable post-quantum encryption (default: enabled)
|
|
73
|
+
NLMCP_USE_POST_QUANTUM=true
|
|
74
|
+
|
|
75
|
+
# Provide your own classical key (optional)
|
|
76
|
+
NLMCP_ENCRYPTION_KEY=<base64-32-bytes>
|
|
77
|
+
|
|
78
|
+
# Disable encryption entirely (NOT recommended)
|
|
79
|
+
NLMCP_ENCRYPTION_ENABLED=false
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Automatic Migration
|
|
83
|
+
|
|
84
|
+
When you upgrade, existing unencrypted files are automatically:
|
|
85
|
+
1. Loaded
|
|
86
|
+
2. Re-encrypted with ML-KEM-768 + ChaCha20-Poly1305
|
|
87
|
+
3. Old unencrypted files are deleted
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Secrets Scanning (NEW)
|
|
92
|
+
|
|
93
|
+
Real-time detection of credentials in logs and responses using patterns from TruffleHog and GitLeaks.
|
|
94
|
+
|
|
95
|
+
### Detected Secret Types
|
|
96
|
+
|
|
97
|
+
| Category | Types |
|
|
98
|
+
|----------|-------|
|
|
99
|
+
| Cloud | AWS Access Keys, GCP API Keys, Azure Tokens |
|
|
100
|
+
| AI Services | OpenAI, Anthropic, Google AI API keys |
|
|
101
|
+
| Source Control | GitHub PATs, GitLab tokens |
|
|
102
|
+
| Communication | Slack tokens/webhooks |
|
|
103
|
+
| Payment | Stripe API keys |
|
|
104
|
+
| Auth | JWTs, Bearer tokens, Basic Auth |
|
|
105
|
+
| Databases | PostgreSQL, MongoDB, MySQL connection strings |
|
|
106
|
+
| Keys | RSA, EC, SSH, PGP private keys |
|
|
107
|
+
|
|
108
|
+
### Configuration
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
NLMCP_SECRETS_SCANNING=true # Enable scanning (default: true)
|
|
112
|
+
NLMCP_SECRETS_BLOCK=false # Block on detection (default: false, just warn)
|
|
113
|
+
NLMCP_SECRETS_REDACT=true # Auto-redact secrets (default: true)
|
|
114
|
+
NLMCP_SECRETS_MIN_SEVERITY=low # Minimum severity: critical, high, medium, low
|
|
115
|
+
NLMCP_SECRETS_IGNORE=pattern1,pattern2 # Ignore specific patterns
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Example Detection
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
🔐 Secrets detected: 1 critical, 0 high
|
|
122
|
+
- AWS Access Key ID at line 42
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Certificate Pinning (NEW)
|
|
128
|
+
|
|
129
|
+
Protects HTTPS connections to Google by validating server certificate chains against known-good SPKI hashes.
|
|
130
|
+
|
|
131
|
+
### Why Certificate Pinning?
|
|
132
|
+
|
|
133
|
+
Prevents man-in-the-middle attacks even if:
|
|
134
|
+
- A rogue CA certificate is installed on the system
|
|
135
|
+
- Corporate proxies attempt SSL inspection
|
|
136
|
+
- DNS is compromised
|
|
137
|
+
|
|
138
|
+
### Pinned Certificates
|
|
139
|
+
|
|
140
|
+
- **GTS Root R1-R4** - Google Trust Services roots
|
|
141
|
+
- **GlobalSign Root CA R2** - Backup root
|
|
142
|
+
- **DigiCert Global Root G2** - Backup root
|
|
143
|
+
|
|
144
|
+
### Configuration
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
NLMCP_CERT_PINNING=true # Enable pinning (default: true)
|
|
148
|
+
NLMCP_CERT_FAIL_OPEN=false # Allow on failure (default: false)
|
|
149
|
+
NLMCP_CERT_REPORT_ONLY=false # Log but don't block (default: false)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Violation Response
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
🔒 Certificate pinning violation for notebooklm.google.com
|
|
156
|
+
Chain hashes: abc123...
|
|
157
|
+
Expected one of: hxqRlP..., Vfd95B...
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Memory Scrubbing (NEW)
|
|
163
|
+
|
|
164
|
+
Sensitive data is securely wiped from memory after use to prevent:
|
|
165
|
+
- Memory dump attacks
|
|
166
|
+
- Cold boot attacks
|
|
167
|
+
- Credential persistence in RAM
|
|
168
|
+
|
|
169
|
+
### Features
|
|
170
|
+
|
|
171
|
+
| Feature | Description |
|
|
172
|
+
|---------|-------------|
|
|
173
|
+
| `zeroBuffer()` | Securely zero-fill Buffer objects |
|
|
174
|
+
| `SecureString` | String wrapper with `.wipe()` method |
|
|
175
|
+
| `SecureCredential` | Auto-expiring credential with timer |
|
|
176
|
+
| `SecureObject` | Object with dispose-and-wipe capability |
|
|
177
|
+
| `secureCompare()` | Timing-safe string comparison |
|
|
178
|
+
|
|
179
|
+
### Auto-cleanup
|
|
180
|
+
|
|
181
|
+
Using `FinalizationRegistry`, secure buffers are automatically wiped when garbage collected.
|
|
182
|
+
|
|
183
|
+
### Usage
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { SecureCredential, withSecureCredential } from './utils/secure-memory.js';
|
|
187
|
+
|
|
188
|
+
// Auto-wipe after 5 minutes
|
|
189
|
+
const cred = new SecureCredential(apiKey, 300000);
|
|
190
|
+
|
|
191
|
+
// Or use helper that auto-wipes after function completes
|
|
192
|
+
await withSecureCredential(apiKey, async (cred) => {
|
|
193
|
+
await makeRequest(cred.getValue());
|
|
194
|
+
});
|
|
195
|
+
// Credential is now wiped
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## MEDUSA Integration (NEW)
|
|
201
|
+
|
|
202
|
+
Automated security scanning using [MEDUSA](https://github.com/Pantheon-Security/medusa) - Multi-Language Security Scanner with 46+ analyzers.
|
|
203
|
+
|
|
204
|
+
### Quick Scan
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm run security-scan
|
|
208
|
+
# or
|
|
209
|
+
medusa scan . --fail-on high
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Configuration
|
|
213
|
+
|
|
214
|
+
See `.medusa.yml` in project root.
|
|
215
|
+
|
|
216
|
+
### CI/CD Integration
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
# GitHub Actions
|
|
220
|
+
- name: Security Scan
|
|
221
|
+
run: npm run security-scan
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Audit Logging
|
|
227
|
+
|
|
228
|
+
All events are logged with cryptographic integrity:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
~/.local/share/notebooklm-mcp/audit/
|
|
232
|
+
├── audit-2025-11-28.jsonl
|
|
233
|
+
└── ...
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Log Format (JSONL with hash chain)
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{"timestamp":"2025-11-28T10:30:00Z","type":"tool","event":"ask_question","success":true,"duration_ms":3420,"hash":"a1b2c3..."}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Each entry's hash includes the previous entry, making tampering detectable.
|
|
243
|
+
|
|
244
|
+
### Configuration
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
NLMCP_AUDIT_ENABLED=true # Default: true
|
|
248
|
+
NLMCP_AUDIT_DIR=/path/to/audit # Default: ~/.local/share/notebooklm-mcp/audit
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Session Timeout
|
|
254
|
+
|
|
255
|
+
Sessions are protected by dual timeout enforcement:
|
|
256
|
+
|
|
257
|
+
| Timeout | Default | Purpose |
|
|
258
|
+
|---------|---------|---------|
|
|
259
|
+
| Max Lifetime | 8 hours | Hard limit regardless of activity |
|
|
260
|
+
| Inactivity | 30 minutes | Closes idle sessions |
|
|
261
|
+
|
|
262
|
+
### Configuration
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
NLMCP_SESSION_MAX_LIFETIME=28800 # 8 hours in seconds
|
|
266
|
+
NLMCP_SESSION_INACTIVITY=1800 # 30 minutes in seconds
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## MCP Authentication
|
|
272
|
+
|
|
273
|
+
Require authentication for all MCP requests.
|
|
274
|
+
|
|
275
|
+
### Setup
|
|
276
|
+
|
|
277
|
+
On first run with auth enabled, a token is auto-generated:
|
|
278
|
+
```
|
|
279
|
+
╔════════════════════════════════════════════════════════════╗
|
|
280
|
+
║ NEW MCP AUTHENTICATION TOKEN GENERATED ║
|
|
281
|
+
╠════════════════════════════════════════════════════════════╣
|
|
282
|
+
║ Token: <your-token> ║
|
|
283
|
+
╠════════════════════════════════════════════════════════════╣
|
|
284
|
+
║ Add to your MCP client config: ║
|
|
285
|
+
║ NLMCP_AUTH_TOKEN=<token> ║
|
|
286
|
+
╚════════════════════════════════════════════════════════════╝
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Claude Code Configuration
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
claude mcp add notebooklm \
|
|
293
|
+
--env NLMCP_AUTH_ENABLED=true \
|
|
294
|
+
--env NLMCP_AUTH_TOKEN=<your-token> \
|
|
295
|
+
npx notebooklm-mcp-secure
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Rate Limiting for Failed Auth
|
|
299
|
+
|
|
300
|
+
- 5 failed attempts = 5 minute lockout
|
|
301
|
+
- Prevents brute force attacks
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Response Validation
|
|
306
|
+
|
|
307
|
+
All responses from NotebookLM are scanned for:
|
|
308
|
+
|
|
309
|
+
### Prompt Injection Detection
|
|
310
|
+
- `ignore previous instructions`
|
|
311
|
+
- `you are now in [mode]`
|
|
312
|
+
- `system:` injections
|
|
313
|
+
- Chat template delimiters (`[INST]`, `<|im_start|>`)
|
|
314
|
+
|
|
315
|
+
### Suspicious URL Detection
|
|
316
|
+
- URL shorteners (bit.ly, tinyurl)
|
|
317
|
+
- Paste services (pastebin)
|
|
318
|
+
- File/JavaScript protocols
|
|
319
|
+
- Raw IP addresses
|
|
320
|
+
- Webhook URLs
|
|
321
|
+
|
|
322
|
+
### Encoded Payload Detection
|
|
323
|
+
- Long Base64 strings
|
|
324
|
+
- Hex encoded data
|
|
325
|
+
- Heavy URL encoding
|
|
326
|
+
- Unicode escape sequences
|
|
327
|
+
|
|
328
|
+
### Configuration
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
NLMCP_RESPONSE_VALIDATION=true
|
|
332
|
+
NLMCP_BLOCK_PROMPT_INJECTION=true
|
|
333
|
+
NLMCP_BLOCK_SUSPICIOUS_URLS=true
|
|
334
|
+
NLMCP_BLOCK_ENCODED_PAYLOADS=false # Just warn by default
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Input Validation
|
|
340
|
+
|
|
341
|
+
All user inputs are validated:
|
|
342
|
+
|
|
343
|
+
| Input | Validation |
|
|
344
|
+
|-------|-----------|
|
|
345
|
+
| `notebook_url` | HTTPS only, domain whitelist (notebooklm.google.com variants) |
|
|
346
|
+
| `notebook_id` | Alphanumeric + dashes only, max 128 chars |
|
|
347
|
+
| `session_id` | Alphanumeric + dashes only, max 64 chars |
|
|
348
|
+
| `question` | Non-empty, max 32,000 chars |
|
|
349
|
+
|
|
350
|
+
### URL Whitelisting
|
|
351
|
+
|
|
352
|
+
Allowed domains:
|
|
353
|
+
- `notebooklm.google.com`
|
|
354
|
+
- Regional variants (`.co.uk`, `.de`, `.fr`, etc.)
|
|
355
|
+
|
|
356
|
+
Blocked:
|
|
357
|
+
- `javascript:` URLs
|
|
358
|
+
- `data:` URLs
|
|
359
|
+
- `file:` URLs
|
|
360
|
+
- Non-HTTPS URLs
|
|
361
|
+
- Path traversal attempts
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Log Sanitization
|
|
366
|
+
|
|
367
|
+
Sensitive data is masked in all log output:
|
|
368
|
+
- Email: `j***n@example.com`
|
|
369
|
+
- Passwords: `[REDACTED]`
|
|
370
|
+
- API keys: `[REDACTED]`
|
|
371
|
+
- Tokens: `[REDACTED]`
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Rate Limiting
|
|
376
|
+
|
|
377
|
+
Built-in rate limiting prevents abuse:
|
|
378
|
+
- 100 requests per minute per session
|
|
379
|
+
- Configurable via `RateLimiter` class
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Remaining Considerations
|
|
384
|
+
|
|
385
|
+
### Browser Automation Risks
|
|
386
|
+
|
|
387
|
+
This MCP uses browser automation (Patchright) which:
|
|
388
|
+
- May violate Google's Terms of Service
|
|
389
|
+
- Could be detected and blocked
|
|
390
|
+
|
|
391
|
+
**Recommendations:**
|
|
392
|
+
- Use a dedicated Google account (not your primary)
|
|
393
|
+
- Run in an isolated environment (VM or container)
|
|
394
|
+
|
|
395
|
+
### Not Encrypted (Chrome Profile)
|
|
396
|
+
|
|
397
|
+
The Chrome profile directory itself is not fully encrypted:
|
|
398
|
+
- `~/.local/share/notebooklm-mcp/chrome_profile/`
|
|
399
|
+
|
|
400
|
+
The sensitive state files (cookies, session) ARE encrypted with post-quantum cryptography.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Quick Start
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# Install
|
|
408
|
+
npm install notebooklm-mcp-secure
|
|
409
|
+
|
|
410
|
+
# Or with Claude Code
|
|
411
|
+
claude mcp add notebooklm npx notebooklm-mcp-secure@latest
|
|
412
|
+
|
|
413
|
+
# With all security features
|
|
414
|
+
claude mcp add notebooklm \
|
|
415
|
+
--env NLMCP_AUTH_ENABLED=true \
|
|
416
|
+
--env NLMCP_AUTH_TOKEN=$(openssl rand -base64 32) \
|
|
417
|
+
--env NLMCP_USE_POST_QUANTUM=true \
|
|
418
|
+
npx notebooklm-mcp-secure@latest
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Security Module API
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// Input validation & rate limiting
|
|
427
|
+
import {
|
|
428
|
+
validateNotebookUrl,
|
|
429
|
+
validateSessionId,
|
|
430
|
+
validateQuestion,
|
|
431
|
+
sanitizeForLogging,
|
|
432
|
+
maskEmail,
|
|
433
|
+
RateLimiter,
|
|
434
|
+
SecurityError,
|
|
435
|
+
} from './utils/security.js';
|
|
436
|
+
|
|
437
|
+
// Post-quantum encryption (ML-KEM-768 + ChaCha20-Poly1305)
|
|
438
|
+
import {
|
|
439
|
+
getSecureStorage,
|
|
440
|
+
SecureStorage,
|
|
441
|
+
encryptPQ,
|
|
442
|
+
decryptPQ,
|
|
443
|
+
generatePQKeyPair,
|
|
444
|
+
} from './utils/crypto.js';
|
|
445
|
+
|
|
446
|
+
// Response validation & prompt injection detection
|
|
447
|
+
import { getResponseValidator, validateResponse } from './utils/response-validator.js';
|
|
448
|
+
|
|
449
|
+
// Tamper-evident audit logging
|
|
450
|
+
import { getAuditLogger, audit } from './utils/audit-logger.js';
|
|
451
|
+
|
|
452
|
+
// MCP token authentication
|
|
453
|
+
import { getMCPAuthenticator, authenticateMCPRequest } from './auth/mcp-auth.js';
|
|
454
|
+
|
|
455
|
+
// Secrets scanning
|
|
456
|
+
import {
|
|
457
|
+
SecretsScanner,
|
|
458
|
+
scanForSecrets,
|
|
459
|
+
scanAndRedactSecrets,
|
|
460
|
+
} from './utils/secrets-scanner.js';
|
|
461
|
+
|
|
462
|
+
// Certificate pinning
|
|
463
|
+
import {
|
|
464
|
+
CertificatePinningManager,
|
|
465
|
+
getCertificatePinningManager,
|
|
466
|
+
validateCertificatePin,
|
|
467
|
+
} from './utils/cert-pinning.js';
|
|
468
|
+
|
|
469
|
+
// Memory security
|
|
470
|
+
import {
|
|
471
|
+
SecureString,
|
|
472
|
+
SecureCredential,
|
|
473
|
+
SecureObject,
|
|
474
|
+
zeroBuffer,
|
|
475
|
+
withSecureCredential,
|
|
476
|
+
secureCompare,
|
|
477
|
+
} from './utils/secure-memory.js';
|
|
478
|
+
|
|
479
|
+
// === USAGE EXAMPLES ===
|
|
480
|
+
|
|
481
|
+
// Post-quantum encrypted storage
|
|
482
|
+
const storage = getSecureStorage();
|
|
483
|
+
await storage.save('/path/to/file', sensitiveData);
|
|
484
|
+
const data = await storage.load('/path/to/file');
|
|
485
|
+
|
|
486
|
+
// Direct post-quantum encryption
|
|
487
|
+
const keyPair = generatePQKeyPair();
|
|
488
|
+
const encrypted = encryptPQ('secret data', keyPair.publicKey);
|
|
489
|
+
const decrypted = decryptPQ(encrypted, keyPair.secretKey);
|
|
490
|
+
|
|
491
|
+
// Secrets scanning
|
|
492
|
+
const secrets = scanForSecrets(responseText);
|
|
493
|
+
if (secrets.length > 0) {
|
|
494
|
+
console.log('Found secrets:', secrets.map(s => s.type));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Auto-redact secrets
|
|
498
|
+
const { clean, secrets: found } = await scanAndRedactSecrets(responseText);
|
|
499
|
+
|
|
500
|
+
// Memory-safe credential handling
|
|
501
|
+
await withSecureCredential(apiKey, async (cred) => {
|
|
502
|
+
await makeRequest(cred.getValue());
|
|
503
|
+
}); // Auto-wiped after use
|
|
504
|
+
|
|
505
|
+
// Timing-safe comparison (prevents timing attacks)
|
|
506
|
+
if (secureCompare(userToken, storedToken)) {
|
|
507
|
+
// Authenticated
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Response validation
|
|
511
|
+
const result = await validateResponse(notebookLMResponse);
|
|
512
|
+
if (!result.safe) {
|
|
513
|
+
console.log('Blocked:', result.blocked);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Audit logging
|
|
517
|
+
await audit.tool('ask_question', true, 3420, { question_length: 150 });
|
|
518
|
+
await audit.security('prompt_injection_detected', 'critical', { pattern: '...' });
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Reporting Vulnerabilities
|
|
524
|
+
|
|
525
|
+
If you discover a security vulnerability:
|
|
526
|
+
- Email: support@pantheonsecurity.io
|
|
527
|
+
- Do NOT open a public GitHub issue for security vulnerabilities
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Credits
|
|
532
|
+
|
|
533
|
+
- Original implementation: [Gérôme Dexheimer](https://github.com/PleasePrompto)
|
|
534
|
+
- Security hardening: [Pantheon Security](https://pantheonsecurity.io)
|
|
535
|
+
- Post-quantum crypto: [@noble/post-quantum](https://www.npmjs.com/package/@noble/post-quantum)
|
|
536
|
+
|
|
537
|
+
## License
|
|
538
|
+
|
|
539
|
+
MIT License (same as original)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication Manager for NotebookLM
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Interactive login (headful browser for setup)
|
|
6
|
+
* - Auto-login with credentials (email/password from ENV)
|
|
7
|
+
* - Browser state persistence (cookies + localStorage + sessionStorage)
|
|
8
|
+
* - Cookie expiry validation
|
|
9
|
+
* - State expiry checks (24h file age)
|
|
10
|
+
* - Hard reset for clean start
|
|
11
|
+
*
|
|
12
|
+
* Based on the Python implementation from auth.py
|
|
13
|
+
*/
|
|
14
|
+
import type { BrowserContext, Page } from "patchright";
|
|
15
|
+
import type { ProgressCallback } from "../types.js";
|
|
16
|
+
export declare class AuthManager {
|
|
17
|
+
private stateFilePath;
|
|
18
|
+
private sessionFilePath;
|
|
19
|
+
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Save entire browser state (cookies + localStorage)
|
|
22
|
+
* Uses post-quantum encrypted storage for sensitive auth data
|
|
23
|
+
*/
|
|
24
|
+
saveBrowserState(context: BrowserContext, page?: Page): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Check if saved browser state exists (encrypted or unencrypted)
|
|
27
|
+
*/
|
|
28
|
+
hasSavedState(): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Get path to saved browser state (checks encrypted versions too)
|
|
31
|
+
*/
|
|
32
|
+
getStatePath(): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Get valid state path (checks expiry)
|
|
35
|
+
*/
|
|
36
|
+
getValidStatePath(): Promise<string | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Load sessionStorage from file (decrypts if encrypted)
|
|
39
|
+
*/
|
|
40
|
+
loadSessionStorage(): Promise<Record<string, string> | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Validate if saved state is still valid
|
|
43
|
+
*/
|
|
44
|
+
validateState(context: BrowserContext): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Validate if critical authentication cookies are still valid
|
|
47
|
+
*/
|
|
48
|
+
validateCookiesExpiry(context: BrowserContext): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Check if the saved state file is too old (>24 hours)
|
|
51
|
+
*/
|
|
52
|
+
isStateExpired(): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Perform interactive login
|
|
55
|
+
* User will see a browser window and login manually
|
|
56
|
+
*
|
|
57
|
+
* SIMPLE & RELIABLE: Just wait for URL to change to notebooklm.google.com
|
|
58
|
+
*/
|
|
59
|
+
performLogin(page: Page, sendProgress?: ProgressCallback): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Attempt to authenticate using configured credentials
|
|
62
|
+
*/
|
|
63
|
+
loginWithCredentials(context: BrowserContext, page: Page, email: string, password: string): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Wait for Google to redirect to NotebookLM after successful login (SIMPLE & RELIABLE)
|
|
66
|
+
*
|
|
67
|
+
* Just checks if URL changes to notebooklm.google.com - no complex UI element searching!
|
|
68
|
+
* Matches the simplified approach used in performLogin().
|
|
69
|
+
*/
|
|
70
|
+
private waitForRedirectAfterLogin;
|
|
71
|
+
/**
|
|
72
|
+
* Wait for NotebookLM to load (SIMPLE & RELIABLE)
|
|
73
|
+
*
|
|
74
|
+
* Just checks if URL starts with notebooklm.google.com - no complex UI element searching!
|
|
75
|
+
* Matches the simplified approach used in performLogin().
|
|
76
|
+
*/
|
|
77
|
+
private waitForNotebook;
|
|
78
|
+
/**
|
|
79
|
+
* Handle possible account chooser
|
|
80
|
+
*/
|
|
81
|
+
private handleAccountChooser;
|
|
82
|
+
/**
|
|
83
|
+
* Fill email identifier field with human-like typing
|
|
84
|
+
*/
|
|
85
|
+
private fillIdentifier;
|
|
86
|
+
/**
|
|
87
|
+
* Fill password field with human-like typing
|
|
88
|
+
*/
|
|
89
|
+
private fillPassword;
|
|
90
|
+
/**
|
|
91
|
+
* Click text element
|
|
92
|
+
*/
|
|
93
|
+
private clickText;
|
|
94
|
+
/**
|
|
95
|
+
* Load authentication state from a specific file path (decrypts if encrypted)
|
|
96
|
+
*/
|
|
97
|
+
loadAuthState(context: BrowserContext, statePath: string): Promise<boolean>;
|
|
98
|
+
/**
|
|
99
|
+
* Perform interactive setup (for setup_auth tool)
|
|
100
|
+
* Opens a PERSISTENT browser for manual login
|
|
101
|
+
*
|
|
102
|
+
* CRITICAL: Uses the SAME persistent context as runtime!
|
|
103
|
+
* This ensures cookies are automatically saved to the Chrome profile.
|
|
104
|
+
*
|
|
105
|
+
* Benefits over temporary browser:
|
|
106
|
+
* - Session cookies persist correctly (Playwright bug workaround)
|
|
107
|
+
* - Same fingerprint as runtime
|
|
108
|
+
* - No need for addCookies() workarounds
|
|
109
|
+
* - Automatic cookie persistence via Chrome profile
|
|
110
|
+
*
|
|
111
|
+
* @param sendProgress Optional progress callback
|
|
112
|
+
* @param overrideHeadless Optional override for headless mode (true = visible, false = headless)
|
|
113
|
+
* If not provided, defaults to true (visible) for setup
|
|
114
|
+
*/
|
|
115
|
+
performSetup(sendProgress?: ProgressCallback, overrideHeadless?: boolean): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Clear ALL authentication data for account switching
|
|
118
|
+
*
|
|
119
|
+
* CRITICAL: This deletes EVERYTHING to ensure only ONE account is active:
|
|
120
|
+
* - All state files (encrypted .pqenc, .enc, and unencrypted .json)
|
|
121
|
+
* - sessionStorage files
|
|
122
|
+
* - Chrome profile directory (browser fingerprint, cache, etc.)
|
|
123
|
+
* - Post-quantum key pairs
|
|
124
|
+
*
|
|
125
|
+
* Use this BEFORE authenticating a new account!
|
|
126
|
+
*/
|
|
127
|
+
clearAllAuthData(): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Clear all saved authentication state (including encrypted versions)
|
|
130
|
+
*/
|
|
131
|
+
clearState(): Promise<boolean>;
|
|
132
|
+
/**
|
|
133
|
+
* HARD RESET: Completely delete ALL authentication state
|
|
134
|
+
*/
|
|
135
|
+
hardResetState(): Promise<boolean>;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=auth-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../../src/auth/auth-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAmBpD,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAS;;IAWhC;;;OAGG;IACG,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAmD9E;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAKvC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAQ7B;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAejD;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAuBlE;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAoC9D;;OAEG;IACG,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAiDtE;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAsBxC;;;;;OAKG;IACG,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAmFjF;;OAEG;IACG,oBAAoB,CACxB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC;IA2InB;;;;;OAKG;YACW,yBAAyB;IA4BvC;;;;;OAKG;YACW,eAAe;IAsB7B;;OAEG;YACW,oBAAoB;IA+BlC;;OAEG;YACW,cAAc;IA2H5B;;OAEG;YACW,YAAY;IA+F1B;;OAEG;YACW,SAAS;IAuBvB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BjF;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,YAAY,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAoEjG;;;;;;;;;;OAUG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+CvC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBpC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAgDzC"}
|