guardvibe 0.4.0 → 0.5.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/README.md +35 -14
- package/build/cli.js +1 -1
- package/build/data/framework-guides.d.ts.map +1 -1
- package/build/data/framework-guides.js +289 -0
- package/build/data/framework-guides.js.map +1 -1
- package/build/data/rules/cicd.d.ts +3 -0
- package/build/data/rules/cicd.d.ts.map +1 -0
- package/build/data/rules/cicd.js +47 -0
- package/build/data/rules/cicd.js.map +1 -0
- package/build/data/rules/core.d.ts.map +1 -1
- package/build/data/rules/core.js +26 -1
- package/build/data/rules/core.js.map +1 -1
- package/build/data/rules/dockerfile.d.ts +3 -0
- package/build/data/rules/dockerfile.d.ts.map +1 -0
- package/build/data/rules/dockerfile.js +58 -0
- package/build/data/rules/dockerfile.js.map +1 -0
- package/build/data/rules/go.d.ts.map +1 -1
- package/build/data/rules/go.js +6 -0
- package/build/data/rules/go.js.map +1 -1
- package/build/data/rules/index.d.ts.map +1 -1
- package/build/data/rules/index.js +4 -0
- package/build/data/rules/index.js.map +1 -1
- package/build/data/rules/java.d.ts.map +1 -1
- package/build/data/rules/java.js +6 -0
- package/build/data/rules/java.js.map +1 -1
- package/build/data/rules/php.d.ts.map +1 -1
- package/build/data/rules/php.js +5 -0
- package/build/data/rules/php.js.map +1 -1
- package/build/data/rules/ruby.d.ts.map +1 -1
- package/build/data/rules/ruby.js +5 -0
- package/build/data/rules/ruby.js.map +1 -1
- package/build/data/rules/types.d.ts +1 -0
- package/build/data/rules/types.d.ts.map +1 -1
- package/build/index.js +8 -2
- package/build/index.js.map +1 -1
- package/build/tools/check-code.d.ts +2 -2
- package/build/tools/check-code.d.ts.map +1 -1
- package/build/tools/check-code.js +10 -5
- package/build/tools/check-code.js.map +1 -1
- package/build/tools/check-project.d.ts.map +1 -1
- package/build/tools/check-project.js +10 -3
- package/build/tools/check-project.js.map +1 -1
- package/build/tools/scan-directory.d.ts.map +1 -1
- package/build/tools/scan-directory.js +13 -4
- package/build/tools/scan-directory.js.map +1 -1
- package/build/tools/scan-staged.d.ts +2 -0
- package/build/tools/scan-staged.d.ts.map +1 -0
- package/build/tools/scan-staged.js +119 -0
- package/build/tools/scan-staged.js.map +1 -0
- package/package.json +1 -1
- package/build/data/owasp-rules.d.ts +0 -12
- package/build/data/owasp-rules.d.ts.map +0 -1
- package/build/data/owasp-rules.js +0 -469
- package/build/data/owasp-rules.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,15 +6,19 @@ Stop shipping vulnerable code. GuardVibe checks your code against OWASP Top 10,
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Code Security Analysis** —
|
|
10
|
-
- **Directory Scanning** — Scan your entire project
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
9
|
+
- **Code Security Analysis** — 55+ vulnerability patterns with auto-fix code snippets
|
|
10
|
+
- **Directory Scanning** — Scan your entire project directly from the filesystem (A-F security score)
|
|
11
|
+
- **Pre-Commit Scanning** — Scan only git-staged files before committing
|
|
12
|
+
- **Secret Detection** — Pattern + entropy-based detection of leaked API keys, tokens, and credentials
|
|
13
|
+
- **Dockerfile Scanning** — Detect root containers, exposed secrets, unpinned images, COPY ordering
|
|
14
|
+
- **CI/CD Scanning** — GitHub Actions security: secrets in run steps, unpinned actions, permissions
|
|
15
|
+
- **Dependency CVE Check** — Parse lockfiles and batch-query Google's OSV database
|
|
16
|
+
- **Auto-Fix Code** — Every finding includes copy-paste-ready secure code
|
|
17
|
+
- **False Positive Suppression** — `// guardvibe-ignore VG001` comments
|
|
18
|
+
- **14 Security Guides** — Express, Next.js, FastAPI, Django, NestJS, Hono, Supabase, tRPC, React, and more
|
|
19
|
+
- **8 Languages + Dockerfile + YAML** — JS, TS, Python, Go, Java, PHP, Ruby, Dockerfile, GitHub Actions
|
|
20
|
+
- **OWASP Top 10:2025** — All rules mapped to latest standards
|
|
21
|
+
- **Zero-Config Setup** — `npx guardvibe init claude`
|
|
18
22
|
|
|
19
23
|
## Quick Start
|
|
20
24
|
|
|
@@ -85,6 +89,14 @@ Input: { topic: "express authentication" | "sql injection" | "nextjs csrf" | ...
|
|
|
85
89
|
Output: Markdown guide with code examples
|
|
86
90
|
```
|
|
87
91
|
|
|
92
|
+
### `scan_staged`
|
|
93
|
+
Scan git-staged files before committing. No input needed.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Input: {} (automatic — reads git staged files)
|
|
97
|
+
Output: Pre-commit security report with A-F score
|
|
98
|
+
```
|
|
99
|
+
|
|
88
100
|
### `scan_directory`
|
|
89
101
|
Scan an entire project directory directly from the filesystem. No need to pass file contents.
|
|
90
102
|
|
|
@@ -131,8 +143,13 @@ Output: Vulnerability report with CVE IDs, severity, and fix versions
|
|
|
131
143
|
| XSS | DOM sanitization, CSP, React escaping |
|
|
132
144
|
| Authentication | bcrypt, JWT, OAuth, session security |
|
|
133
145
|
| Environment Variables | .env management, Vercel, secret rotation |
|
|
146
|
+
| Django | CSRF, ORM, settings, ALLOWED_HOSTS, password hashing |
|
|
147
|
+
| NestJS | Guards, Helmet, ValidationPipe, rate limiting |
|
|
148
|
+
| Hono | Middleware auth, CORS, zod validation, secure headers |
|
|
149
|
+
| Supabase | Row Level Security, anon vs service key, auth |
|
|
150
|
+
| tRPC | Input validation, auth middleware, rate limiting |
|
|
134
151
|
|
|
135
|
-
## Security Rules (
|
|
152
|
+
## Security Rules (55+ patterns)
|
|
136
153
|
|
|
137
154
|
### Core Rules (All supported languages)
|
|
138
155
|
|
|
@@ -157,6 +174,8 @@ Output: Vulnerability report with CVE IDs, severity, and fix versions
|
|
|
157
174
|
| VG120-VG125 | Java | SQL concat, Runtime.exec, JSP XSS, Spring auth, MessageDigest, @CrossOrigin |
|
|
158
175
|
| VG130-VG134 | PHP | $_GET/$_POST SQL injection, shell_exec, echo XSS, md5/sha1, eval |
|
|
159
176
|
| VG140-VG144 | Ruby | String interpolation SQL, backtick injection, html_safe XSS, route auth, Digest |
|
|
177
|
+
| VG200-VG204 | Dockerfile | Root container, COPY ordering, latest tag, secrets in ENV, ADD vs COPY |
|
|
178
|
+
| VG210-VG213 | GitHub Actions | Secrets in run steps, pull_request_target, unpinned actions, permissions |
|
|
160
179
|
|
|
161
180
|
## Suppressing False Positives
|
|
162
181
|
|
|
@@ -180,11 +199,13 @@ Supports `//`, `#`, and `<!-- -->` comment styles.
|
|
|
180
199
|
|
|
181
200
|
GuardVibe runs as a local MCP server (stdio transport). When your AI assistant needs security guidance, it calls GuardVibe's tools:
|
|
182
201
|
|
|
183
|
-
1. **Writing code?** → `check_code` scans for vulnerability patterns
|
|
202
|
+
1. **Writing code?** → `check_code` scans for vulnerability patterns with auto-fix
|
|
184
203
|
2. **Reviewing a project?** → `scan_directory` scans your entire codebase
|
|
185
|
-
3. **
|
|
186
|
-
4. **
|
|
187
|
-
5. **
|
|
204
|
+
3. **About to commit?** → `scan_staged` checks only staged files
|
|
205
|
+
4. **Adding a package?** → `scan_dependencies` checks your lockfile for CVEs
|
|
206
|
+
5. **Worried about leaks?** → `scan_secrets` detects API keys and tokens
|
|
207
|
+
6. **Building Docker?** → `check_code` with language `dockerfile` scans your Dockerfile
|
|
208
|
+
7. **Need guidance?** → `get_security_docs` for 14 framework guides
|
|
188
209
|
|
|
189
210
|
No API keys needed. No cloud dependency. Runs entirely on your machine.
|
|
190
211
|
|
package/build/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-guides.d.ts","sourceRoot":"","sources":["../../src/data/framework-guides.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,eAAO,MAAM,eAAe,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"framework-guides.d.ts","sourceRoot":"","sources":["../../src/data/framework-guides.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,eAAO,MAAM,eAAe,EAAE,aAAa,EA8xB1C,CAAC"}
|
|
@@ -496,5 +496,294 @@ When your AI generates code with hardcoded secrets:
|
|
|
496
496
|
3. Add .env to .gitignore
|
|
497
497
|
4. Tell your AI: "Use environment variables for secrets"`,
|
|
498
498
|
},
|
|
499
|
+
{
|
|
500
|
+
topic: "django",
|
|
501
|
+
title: "Django Security Best Practices",
|
|
502
|
+
keywords: ["django", "python", "csrf", "orm", "settings", "allowed_hosts"],
|
|
503
|
+
content: `# Django Security Best Practices
|
|
504
|
+
|
|
505
|
+
## Critical Settings
|
|
506
|
+
\`\`\`python
|
|
507
|
+
# settings.py
|
|
508
|
+
DEBUG = False # NEVER True in production
|
|
509
|
+
SECRET_KEY = os.environ['DJANGO_SECRET_KEY'] # Never hardcode
|
|
510
|
+
ALLOWED_HOSTS = ['myapp.com'] # Never use ['*']
|
|
511
|
+
SECURE_SSL_REDIRECT = True
|
|
512
|
+
SESSION_COOKIE_SECURE = True
|
|
513
|
+
CSRF_COOKIE_SECURE = True
|
|
514
|
+
SECURE_HSTS_SECONDS = 31536000
|
|
515
|
+
\`\`\`
|
|
516
|
+
|
|
517
|
+
## CSRF Protection
|
|
518
|
+
Django includes CSRF middleware by default. Never disable it.
|
|
519
|
+
\`\`\`python
|
|
520
|
+
# Views that modify data need @csrf_protect or use CsrfViewMiddleware
|
|
521
|
+
from django.views.decorators.csrf import csrf_protect
|
|
522
|
+
|
|
523
|
+
@csrf_protect
|
|
524
|
+
def update_profile(request):
|
|
525
|
+
pass
|
|
526
|
+
\`\`\`
|
|
527
|
+
|
|
528
|
+
## ORM Injection Prevention
|
|
529
|
+
Always use Django ORM — avoid raw SQL:
|
|
530
|
+
\`\`\`python
|
|
531
|
+
# Safe - ORM parameterizes automatically
|
|
532
|
+
User.objects.filter(name=user_input)
|
|
533
|
+
|
|
534
|
+
# Dangerous - raw SQL with interpolation
|
|
535
|
+
User.objects.raw(f"SELECT * FROM users WHERE name = '{user_input}'")
|
|
536
|
+
|
|
537
|
+
# If raw SQL needed, use params:
|
|
538
|
+
User.objects.raw("SELECT * FROM users WHERE name = %s", [user_input])
|
|
539
|
+
\`\`\`
|
|
540
|
+
|
|
541
|
+
## Authentication
|
|
542
|
+
\`\`\`python
|
|
543
|
+
from django.contrib.auth.decorators import login_required
|
|
544
|
+
|
|
545
|
+
@login_required
|
|
546
|
+
def dashboard(request):
|
|
547
|
+
pass
|
|
548
|
+
\`\`\`
|
|
549
|
+
|
|
550
|
+
## Password Hashing
|
|
551
|
+
Django uses PBKDF2 by default. Upgrade to Argon2:
|
|
552
|
+
\`\`\`python
|
|
553
|
+
# settings.py
|
|
554
|
+
PASSWORD_HASHERS = [
|
|
555
|
+
'django.contrib.auth.hashers.Argon2PasswordHasher',
|
|
556
|
+
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
|
|
557
|
+
]
|
|
558
|
+
\`\`\`
|
|
559
|
+
`,
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
topic: "nestjs",
|
|
563
|
+
title: "NestJS Security Best Practices",
|
|
564
|
+
keywords: ["nestjs", "nest", "guard", "pipe", "helmet", "validation"],
|
|
565
|
+
content: `# NestJS Security Best Practices
|
|
566
|
+
|
|
567
|
+
## Helmet
|
|
568
|
+
\`\`\`typescript
|
|
569
|
+
import helmet from 'helmet';
|
|
570
|
+
app.use(helmet());
|
|
571
|
+
\`\`\`
|
|
572
|
+
|
|
573
|
+
## CORS
|
|
574
|
+
\`\`\`typescript
|
|
575
|
+
app.enableCors({
|
|
576
|
+
origin: ['https://myapp.com'],
|
|
577
|
+
credentials: true,
|
|
578
|
+
});
|
|
579
|
+
\`\`\`
|
|
580
|
+
|
|
581
|
+
## Validation Pipe (Global)
|
|
582
|
+
\`\`\`typescript
|
|
583
|
+
app.useGlobalPipes(new ValidationPipe({
|
|
584
|
+
whitelist: true, // Strip unknown properties
|
|
585
|
+
forbidNonWhitelisted: true,
|
|
586
|
+
transform: true,
|
|
587
|
+
}));
|
|
588
|
+
\`\`\`
|
|
589
|
+
|
|
590
|
+
## Auth Guard
|
|
591
|
+
\`\`\`typescript
|
|
592
|
+
@Injectable()
|
|
593
|
+
export class AuthGuard implements CanActivate {
|
|
594
|
+
canActivate(context: ExecutionContext): boolean {
|
|
595
|
+
const request = context.switchToHttp().getRequest();
|
|
596
|
+
return validateToken(request.headers.authorization);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Apply globally or per-route
|
|
601
|
+
@UseGuards(AuthGuard)
|
|
602
|
+
@Controller('api')
|
|
603
|
+
export class ApiController {}
|
|
604
|
+
\`\`\`
|
|
605
|
+
|
|
606
|
+
## Rate Limiting
|
|
607
|
+
\`\`\`typescript
|
|
608
|
+
import { ThrottlerModule } from '@nestjs/throttler';
|
|
609
|
+
@Module({
|
|
610
|
+
imports: [ThrottlerModule.forRoot({ ttl: 60, limit: 10 })],
|
|
611
|
+
})
|
|
612
|
+
\`\`\`
|
|
613
|
+
|
|
614
|
+
## Environment Variables
|
|
615
|
+
\`\`\`typescript
|
|
616
|
+
import { ConfigModule } from '@nestjs/config';
|
|
617
|
+
@Module({
|
|
618
|
+
imports: [ConfigModule.forRoot({ isGlobal: true })],
|
|
619
|
+
})
|
|
620
|
+
// Use: configService.get('DATABASE_URL')
|
|
621
|
+
\`\`\`
|
|
622
|
+
`,
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
topic: "hono",
|
|
626
|
+
title: "Hono Security Best Practices",
|
|
627
|
+
keywords: ["hono", "edge", "middleware", "cloudflare", "bun"],
|
|
628
|
+
content: `# Hono Security Best Practices
|
|
629
|
+
|
|
630
|
+
## CORS
|
|
631
|
+
\`\`\`typescript
|
|
632
|
+
import { cors } from 'hono/cors';
|
|
633
|
+
app.use('*', cors({
|
|
634
|
+
origin: ['https://myapp.com'],
|
|
635
|
+
credentials: true,
|
|
636
|
+
}));
|
|
637
|
+
\`\`\`
|
|
638
|
+
|
|
639
|
+
## Auth Middleware
|
|
640
|
+
\`\`\`typescript
|
|
641
|
+
import { bearerAuth } from 'hono/bearer-auth';
|
|
642
|
+
app.use('/api/*', bearerAuth({ token: process.env.API_TOKEN! }));
|
|
643
|
+
|
|
644
|
+
// Or custom JWT auth:
|
|
645
|
+
app.use('/api/*', async (c, next) => {
|
|
646
|
+
const token = c.req.header('Authorization')?.replace('Bearer ', '');
|
|
647
|
+
if (!token || !verifyJwt(token)) return c.json({ error: 'Unauthorized' }, 401);
|
|
648
|
+
await next();
|
|
649
|
+
});
|
|
650
|
+
\`\`\`
|
|
651
|
+
|
|
652
|
+
## Input Validation
|
|
653
|
+
\`\`\`typescript
|
|
654
|
+
import { zValidator } from '@hono/zod-validator';
|
|
655
|
+
import { z } from 'zod';
|
|
656
|
+
|
|
657
|
+
app.post('/api/users', zValidator('json', z.object({
|
|
658
|
+
email: z.string().email(),
|
|
659
|
+
name: z.string().min(1).max(100),
|
|
660
|
+
})), async (c) => {
|
|
661
|
+
const data = c.req.valid('json');
|
|
662
|
+
});
|
|
663
|
+
\`\`\`
|
|
664
|
+
|
|
665
|
+
## Rate Limiting
|
|
666
|
+
\`\`\`typescript
|
|
667
|
+
import { rateLimiter } from 'hono-rate-limiter';
|
|
668
|
+
app.use(rateLimiter({ windowMs: 15 * 60 * 1000, limit: 100 }));
|
|
669
|
+
\`\`\`
|
|
670
|
+
|
|
671
|
+
## Secure Headers
|
|
672
|
+
\`\`\`typescript
|
|
673
|
+
import { secureHeaders } from 'hono/secure-headers';
|
|
674
|
+
app.use('*', secureHeaders());
|
|
675
|
+
\`\`\`
|
|
676
|
+
`,
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
topic: "supabase",
|
|
680
|
+
title: "Supabase Security Best Practices",
|
|
681
|
+
keywords: ["supabase", "rls", "row level security", "postgres", "auth"],
|
|
682
|
+
content: `# Supabase Security Best Practices
|
|
683
|
+
|
|
684
|
+
## Row Level Security (RLS) — CRITICAL
|
|
685
|
+
Always enable RLS on every table:
|
|
686
|
+
\`\`\`sql
|
|
687
|
+
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
|
|
688
|
+
|
|
689
|
+
-- Users can only read their own profile
|
|
690
|
+
CREATE POLICY "Users read own profile"
|
|
691
|
+
ON profiles FOR SELECT
|
|
692
|
+
USING (auth.uid() = user_id);
|
|
693
|
+
|
|
694
|
+
-- Users can only update their own profile
|
|
695
|
+
CREATE POLICY "Users update own profile"
|
|
696
|
+
ON profiles FOR UPDATE
|
|
697
|
+
USING (auth.uid() = user_id);
|
|
698
|
+
\`\`\`
|
|
699
|
+
|
|
700
|
+
## Anon Key vs Service Key
|
|
701
|
+
\`\`\`typescript
|
|
702
|
+
// Client-side: use anon key (safe to expose, RLS enforced)
|
|
703
|
+
const supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!);
|
|
704
|
+
|
|
705
|
+
// Server-side only: service key (bypasses RLS!)
|
|
706
|
+
const admin = createClient(url, process.env.SUPABASE_SERVICE_KEY!);
|
|
707
|
+
// NEVER expose service key to the client
|
|
708
|
+
\`\`\`
|
|
709
|
+
|
|
710
|
+
## Auth
|
|
711
|
+
\`\`\`typescript
|
|
712
|
+
// Always check auth on server
|
|
713
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
714
|
+
if (!user) throw new Error('Unauthorized');
|
|
715
|
+
\`\`\`
|
|
716
|
+
|
|
717
|
+
## API Security
|
|
718
|
+
\`\`\`typescript
|
|
719
|
+
// Validate input before database operations
|
|
720
|
+
const schema = z.object({ title: z.string().max(200) });
|
|
721
|
+
const input = schema.parse(body);
|
|
722
|
+
await supabase.from('posts').insert(input);
|
|
723
|
+
\`\`\`
|
|
724
|
+
`,
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
topic: "trpc",
|
|
728
|
+
title: "tRPC Security Best Practices",
|
|
729
|
+
keywords: ["trpc", "procedure", "middleware", "zod", "typesafe"],
|
|
730
|
+
content: `# tRPC Security Best Practices
|
|
731
|
+
|
|
732
|
+
## Input Validation
|
|
733
|
+
Always validate with zod:
|
|
734
|
+
\`\`\`typescript
|
|
735
|
+
export const appRouter = router({
|
|
736
|
+
createUser: publicProcedure
|
|
737
|
+
.input(z.object({
|
|
738
|
+
email: z.string().email(),
|
|
739
|
+
name: z.string().min(1).max(100),
|
|
740
|
+
}))
|
|
741
|
+
.mutation(async ({ input }) => {
|
|
742
|
+
// input is validated and typed
|
|
743
|
+
}),
|
|
744
|
+
});
|
|
745
|
+
\`\`\`
|
|
746
|
+
|
|
747
|
+
## Auth Middleware
|
|
748
|
+
\`\`\`typescript
|
|
749
|
+
const isAuthed = t.middleware(({ ctx, next }) => {
|
|
750
|
+
if (!ctx.session?.user) {
|
|
751
|
+
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
752
|
+
}
|
|
753
|
+
return next({ ctx: { user: ctx.session.user } });
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
const protectedProcedure = t.procedure.use(isAuthed);
|
|
757
|
+
|
|
758
|
+
// Use for protected routes
|
|
759
|
+
export const appRouter = router({
|
|
760
|
+
getProfile: protectedProcedure.query(({ ctx }) => {
|
|
761
|
+
return db.user.findUnique({ where: { id: ctx.user.id } });
|
|
762
|
+
}),
|
|
763
|
+
});
|
|
764
|
+
\`\`\`
|
|
765
|
+
|
|
766
|
+
## Rate Limiting
|
|
767
|
+
\`\`\`typescript
|
|
768
|
+
const rateLimiter = t.middleware(async ({ ctx, next }) => {
|
|
769
|
+
const ip = ctx.req.headers['x-forwarded-for'] || 'unknown';
|
|
770
|
+
const { success } = await ratelimit.limit(ip);
|
|
771
|
+
if (!success) throw new TRPCError({ code: 'TOO_MANY_REQUESTS' });
|
|
772
|
+
return next();
|
|
773
|
+
});
|
|
774
|
+
\`\`\`
|
|
775
|
+
|
|
776
|
+
## Error Handling
|
|
777
|
+
Never expose internal errors:
|
|
778
|
+
\`\`\`typescript
|
|
779
|
+
// tRPC automatically masks internal errors in production
|
|
780
|
+
// Only TRPCError messages are sent to client
|
|
781
|
+
throw new TRPCError({
|
|
782
|
+
code: 'BAD_REQUEST',
|
|
783
|
+
message: 'Invalid input', // Safe user-facing message
|
|
784
|
+
});
|
|
785
|
+
\`\`\`
|
|
786
|
+
`,
|
|
787
|
+
},
|
|
499
788
|
];
|
|
500
789
|
//# sourceMappingURL=framework-guides.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-guides.js","sourceRoot":"","sources":["../../src/data/framework-guides.ts"],"names":[],"mappings":"AAOA,iFAAiF;AACjF,kFAAkF;AAElF,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C;QACE,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,wBAAwB,CAAC;QAChF,KAAK,EAAE,qCAAqC;QAC5C,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;wDAwB2C;KACrD;IAED;QACE,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;QAC9E,KAAK,EAAE,oCAAoC;QAC3C,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6EN;KACJ;IAED;QACE,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,YAAY,CAAC;QAC1F,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2DAwE8C;KACxD;IAED;QACE,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;QACvG,KAAK,EAAE,gCAAgC;QACvC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAsCuD;KACjE;IAED;QACE,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,CAAC;QACjF,KAAK,EAAE,uCAAuC;QAC9C,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2DAsC8C;KACxD;IAED;QACE,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC;QACvG,KAAK,EAAE,+BAA+B;QACtC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoDN;KACJ;IAED;QACE,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC;QAC/D,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6DN;KACJ;IAED;QACE,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;QACvF,KAAK,EAAE,+BAA+B;QACtC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4CN;KACJ;IAED;QACE,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC;QACpG,KAAK,EAAE,4CAA4C;QACnD,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAmC4C;KACtD;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"framework-guides.js","sourceRoot":"","sources":["../../src/data/framework-guides.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cicd.d.ts","sourceRoot":"","sources":["../../../src/data/rules/cicd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,SAAS,EAAE,YAAY,EA6CnC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const cicdRules = [
|
|
2
|
+
{
|
|
3
|
+
id: "VG210",
|
|
4
|
+
name: "Secrets interpolated in run step",
|
|
5
|
+
severity: "critical",
|
|
6
|
+
owasp: "A01:2025 Broken Access Control",
|
|
7
|
+
description: "GitHub Actions secrets interpolated directly in run steps can leak via process logs or error messages.",
|
|
8
|
+
pattern: /run:\s*.*\$\{\{\s*secrets\./gi,
|
|
9
|
+
languages: ["yaml"],
|
|
10
|
+
fix: "Pass secrets as environment variables instead of interpolating in run steps.",
|
|
11
|
+
fixCode: "# Pass secrets via env, not interpolation\nsteps:\n - run: echo \"deploying\"\n env:\n MY_SECRET: ${{ secrets.MY_SECRET }}",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "VG211",
|
|
15
|
+
name: "pull_request_target with checkout",
|
|
16
|
+
severity: "critical",
|
|
17
|
+
owasp: "A01:2025 Broken Access Control",
|
|
18
|
+
description: "Using pull_request_target with actions/checkout allows untrusted PR code to access secrets.",
|
|
19
|
+
pattern: /pull_request_target[\s\S]*?actions\/checkout/gi,
|
|
20
|
+
languages: ["yaml"],
|
|
21
|
+
fix: "Use pull_request trigger instead, or avoid checking out PR code with pull_request_target.",
|
|
22
|
+
fixCode: "# Use pull_request instead of pull_request_target\non:\n pull_request:\n branches: [main]",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "VG212",
|
|
26
|
+
name: "Unpinned action version",
|
|
27
|
+
severity: "medium",
|
|
28
|
+
owasp: "A03:2025 Software Supply Chain Failures",
|
|
29
|
+
description: "Using @main or @master for GitHub Actions allows untested code changes to affect your pipeline.",
|
|
30
|
+
pattern: /uses:\s*\S+@(?:main|master)\s/gi,
|
|
31
|
+
languages: ["yaml"],
|
|
32
|
+
fix: "Pin actions to a specific commit SHA or version tag.",
|
|
33
|
+
fixCode: "# Pin to specific version or SHA\nuses: actions/checkout@v4\n# Or pin to commit SHA:\n# uses: actions/checkout@abc123def456",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "VG213",
|
|
37
|
+
name: "Overly permissive permissions",
|
|
38
|
+
severity: "high",
|
|
39
|
+
owasp: "A01:2025 Broken Access Control",
|
|
40
|
+
description: "write-all permissions give the workflow full access to the repository. Use least-privilege permissions.",
|
|
41
|
+
pattern: /permissions:\s*write-all/gi,
|
|
42
|
+
languages: ["yaml"],
|
|
43
|
+
fix: "Specify minimum required permissions for each job.",
|
|
44
|
+
fixCode: "# Use least-privilege permissions\npermissions:\n contents: read\n pull-requests: write",
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
//# sourceMappingURL=cicd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cicd.js","sourceRoot":"","sources":["../../../src/data/rules/cicd.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAmB;IACvC;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,kCAAkC;QACxC,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,gCAAgC;QACvC,WAAW,EAAE,wGAAwG;QACrH,OAAO,EAAE,+BAA+B;QACxC,SAAS,EAAE,CAAC,MAAM,CAAC;QACnB,GAAG,EAAE,8EAA8E;QACnF,OAAO,EAAE,qIAAqI;KAC/I;IACD;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,mCAAmC;QACzC,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,gCAAgC;QACvC,WAAW,EAAE,6FAA6F;QAC1G,OAAO,EAAE,gDAAgD;QACzD,SAAS,EAAE,CAAC,MAAM,CAAC;QACnB,GAAG,EAAE,2FAA2F;QAChG,OAAO,EAAE,+FAA+F;KACzG;IACD;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,yCAAyC;QAChD,WAAW,EAAE,iGAAiG;QAC9G,OAAO,EAAE,iCAAiC;QAC1C,SAAS,EAAE,CAAC,MAAM,CAAC;QACnB,GAAG,EAAE,sDAAsD;QAC3D,OAAO,EAAE,6HAA6H;KACvI;IACD;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,+BAA+B;QACrC,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,gCAAgC;QACvC,WAAW,EAAE,yGAAyG;QACtH,OAAO,EAAE,4BAA4B;QACrC,SAAS,EAAE,CAAC,MAAM,CAAC;QACnB,GAAG,EAAE,oDAAoD;QACzD,OAAO,EAAE,2FAA2F;KACrG;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/data/rules/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,eAAO,MAAM,SAAS,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/data/rules/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,eAAO,MAAM,SAAS,EAAE,YAAY,EA4SnC,CAAC"}
|