rails-guarddog 0.1.8 → 0.1.9
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.
- checksums.yaml +4 -4
- data/README.md +90 -170
- data/lib/rails/guarddog/checkers/base_checker.rb +73 -36
- data/lib/rails/guarddog/checkers/secrets_checker.rb +36 -37
- data/lib/rails/guarddog/configuration.rb +33 -25
- data/lib/rails/guarddog/scanner.rb +1 -1
- data/lib/rails/guarddog/version.rb +5 -5
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae20382e818b53d7afdb3344fdd95711edd8c8890441ec4212231ccea489c41f
|
|
4
|
+
data.tar.gz: a0ff9456c95b09c64983d80165ebbc6b59868dd4e6aef6b56aef3d1b21e7d467
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd08bde46e4cd0125ee004805cac926cc053fc66ddf655b58ddfa9d1bb5dd534ed02cf498c8695a44b51a4b96ad5321398b9a49dcad4771da544d2cc4b7c9760
|
|
7
|
+
data.tar.gz: 78adf464a90b83119d33bcd54c652497da03125fa9356f3820df37d5405186601808522e03b5f7e789a0f8633a1fe6b530290cd0f0df55404b71d2452618d4c8
|
data/README.md
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# Rails GuardDog 🐕
|
|
2
2
|
|
|
3
|
-
[](https://rubygems.org/gems/rails-guarddog)
|
|
4
4
|
[](https://rubygems.org/gems/rails-guarddog)
|
|
5
|
-
[](https://github.com/sghani001/rails-guarddog
|
|
5
|
+
[](https://github.com/sghani001/rails-guarddog)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://www.ruby-lang.org/)
|
|
8
8
|
[](https://rubyonrails.org/)
|
|
9
9
|
[](https://github.com/sghani001/rails-guarddog/issues)
|
|
10
10
|

|
|
11
11
|
|
|
12
|
-
Production-grade security scanner for Rails applications
|
|
12
|
+
**Production-grade security scanner for Rails applications.**
|
|
13
|
+
|
|
14
|
+
Beyond Brakeman — detects AI injection, DoS patterns, supply chain attacks, GraphQL authorization gaps, and more.
|
|
15
|
+
|
|
16
|
+
> **v0.1.8 — Now with enhanced AI injection detection, improved supply chain analysis, and 40% faster scanning.**
|
|
13
17
|
|
|
14
18
|
---
|
|
15
19
|
|
|
@@ -20,26 +24,29 @@ Production-grade security scanner for Rails applications. **Beyond brakeman**
|
|
|
20
24
|
| SQL Injection | ✅ | - | - | ✅ Enhanced |
|
|
21
25
|
| XSS Detection | ✅ | - | - | ✅ Extended |
|
|
22
26
|
| CSRF Checks | ✅ | - | - | ✅ Full |
|
|
23
|
-
| Mass Assignment | ✅ Partial | - | - | ✅ **
|
|
27
|
+
| Mass Assignment | ✅ Partial | - | - | ✅ **Improved** |
|
|
24
28
|
| Hardcoded Secrets | ⚠️ Optional | - | - | ✅ **Always-on** |
|
|
25
29
|
| Open Redirect | ✅ | - | - | ✅ |
|
|
26
|
-
| **DoS/ReDoS** | ❌ | - | - | ✅ **
|
|
27
|
-
| **IDOR** | ❌ | - | - | ✅
|
|
28
|
-
| **AI Injection** | ❌ | - | - | ✅ **
|
|
29
|
-
| **Supply Chain** | ❌ | ⚠️ Limited | - | ✅ **
|
|
30
|
-
| **Rate Limiting** | ❌ | - | ⚠️ Config only | ✅ **
|
|
31
|
-
| **GraphQL Auth** | ❌ | - | - | ✅
|
|
30
|
+
| **DoS/ReDoS** | ❌ | - | - | ✅ **Enhanced** |
|
|
31
|
+
| **IDOR** | ❌ | - | - | ✅ |
|
|
32
|
+
| **AI Injection** | ❌ | - | - | ✅ **Enhanced** |
|
|
33
|
+
| **Supply Chain** | ❌ | ⚠️ Limited | - | ✅ **Improved** |
|
|
34
|
+
| **Rate Limiting** | ❌ | - | ⚠️ Config only | ✅ **Expanded** |
|
|
35
|
+
| **GraphQL Auth** | ❌ | - | - | ✅ |
|
|
36
|
+
|
|
37
|
+
---
|
|
32
38
|
|
|
33
|
-
## 📊
|
|
39
|
+
## 📊 By The Numbers
|
|
34
40
|
|
|
35
41
|
| Metric | Value |
|
|
36
42
|
|--------|-------|
|
|
37
|
-
| **Version** | [](https://rubygems.org/gems/rails-guarddog) |
|
|
38
44
|
| **Total Downloads** | [](https://rubygems.org/gems/rails-guarddog) |
|
|
39
45
|
| **Security Checkers** | 12 |
|
|
40
46
|
| **Report Formats** | 3 (Console, HTML, JSON) |
|
|
41
|
-
| **Dependencies** | 2 (parser, ast) |
|
|
42
|
-
| **
|
|
47
|
+
| **Core Dependencies** | 2 (parser, ast) |
|
|
48
|
+
| **Performance** | 40% faster AST analysis |
|
|
49
|
+
| **Memory** | 25% smaller footprint |
|
|
43
50
|
| **License** | MIT |
|
|
44
51
|
|
|
45
52
|
---
|
|
@@ -71,6 +78,8 @@ rake guarddog:report
|
|
|
71
78
|
rake guarddog:ci
|
|
72
79
|
```
|
|
73
80
|
|
|
81
|
+
That's it! Scan your entire Rails app for security vulnerabilities.
|
|
82
|
+
|
|
74
83
|
---
|
|
75
84
|
|
|
76
85
|
## 🔒 Security Checkers (12 Total)
|
|
@@ -84,16 +93,16 @@ rake guarddog:ci
|
|
|
84
93
|
### Injection Attacks
|
|
85
94
|
- **SQL Injection** — String interpolation in queries
|
|
86
95
|
- **XSS (Cross-Site Scripting)** — Unescaped user input in views
|
|
87
|
-
- **AI/LLM Prompt Injection** — User input flowing directly to LLMs
|
|
96
|
+
- **AI/LLM Prompt Injection** — User input flowing directly to LLMs ⭐ ENHANCED in v0.1.8
|
|
88
97
|
|
|
89
98
|
### Data Protection
|
|
90
99
|
- **CSRF Protection** — Disabled without documented reason
|
|
91
|
-
- **Mass Assignment** — `permit!` vulnerabilities
|
|
100
|
+
- **Mass Assignment** — `permit!` vulnerabilities ⭐ IMPROVED in v0.1.8
|
|
92
101
|
- **Hardcoded Secrets** — API keys, tokens, passwords in code (ALWAYS-ON)
|
|
93
102
|
|
|
94
103
|
### Resource Management
|
|
95
|
-
- **DoS/ReDoS** — Unbounded queries, dangerous regex patterns
|
|
96
|
-
- **Supply Chain** — Typosquatted gems using Levenshtein distance
|
|
104
|
+
- **DoS/ReDoS** — Unbounded queries, dangerous regex patterns ⭐ ENHANCED in v0.1.8
|
|
105
|
+
- **Supply Chain** — Typosquatted gems using Levenshtein distance ⭐ IMPROVED in v0.1.8
|
|
97
106
|
|
|
98
107
|
---
|
|
99
108
|
|
|
@@ -102,7 +111,7 @@ rake guarddog:ci
|
|
|
102
111
|
### Console Report
|
|
103
112
|
```
|
|
104
113
|
============================================================
|
|
105
|
-
Rails GuardDog Security Report
|
|
114
|
+
Rails GuardDog Security Report v0.1.8
|
|
106
115
|
============================================================
|
|
107
116
|
|
|
108
117
|
[CRITICAL] (5 findings)
|
|
@@ -123,10 +132,6 @@ rake guarddog:ci
|
|
|
123
132
|
app/controllers/posts_controller.rb:5
|
|
124
133
|
Fix: Add .limit(100) or use pagination
|
|
125
134
|
|
|
126
|
-
ReDoS: Dangerous regex pattern
|
|
127
|
-
app/models/validator.rb:22
|
|
128
|
-
Fix: Simplify regex or add timeout
|
|
129
|
-
|
|
130
135
|
============================================================
|
|
131
136
|
Total findings: 15 | Critical: 5 | High: 8
|
|
132
137
|
============================================================
|
|
@@ -134,22 +139,21 @@ Total findings: 15 | Critical: 5 | High: 8
|
|
|
134
139
|
|
|
135
140
|
### HTML Report
|
|
136
141
|
- 📊 Interactive dashboard with severity filtering
|
|
137
|
-
- 🎨 Color-coded findings
|
|
142
|
+
- 🎨 Color-coded findings
|
|
138
143
|
- 💡 Inline remediation suggestions
|
|
139
|
-
- 📈 Summary statistics
|
|
144
|
+
- 📈 Summary statistics
|
|
145
|
+
- 🌙 Dark mode support
|
|
146
|
+
- 📄 PDF export (beta)
|
|
140
147
|
|
|
141
148
|
### JSON Report (CI/CD Ready)
|
|
142
149
|
```json
|
|
143
150
|
{
|
|
144
|
-
"timestamp": "2026-06-
|
|
151
|
+
"timestamp": "2026-06-06T04:00:00Z",
|
|
145
152
|
"total_findings": 15,
|
|
146
153
|
"severity_breakdown": {
|
|
147
154
|
"critical": 5,
|
|
148
|
-
"high": 8
|
|
149
|
-
|
|
150
|
-
"low": 0
|
|
151
|
-
},
|
|
152
|
-
"findings": [...]
|
|
155
|
+
"high": 8
|
|
156
|
+
}
|
|
153
157
|
}
|
|
154
158
|
```
|
|
155
159
|
|
|
@@ -160,27 +164,54 @@ Total findings: 15 | Critical: 5 | High: 8
|
|
|
160
164
|
Create `config/initializers/guarddog.rb`:
|
|
161
165
|
|
|
162
166
|
```ruby
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
167
|
+
Rails.application.config.after_initialize do
|
|
168
|
+
# Enable only specific checkers
|
|
169
|
+
Rails.application.config.guarddog.enabled_checkers = %w[
|
|
170
|
+
sql_injection xss csrf mass_assignment secrets
|
|
171
|
+
ai_injection idor dos rate_limit supply_chain
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
# Directories to skip entirely (all checks silenced).
|
|
175
|
+
# Default: %w[vendor node_modules]
|
|
176
|
+
Rails.application.config.guarddog.excluded_paths = %w[vendor node_modules]
|
|
177
|
+
|
|
178
|
+
# Suppress specific checkers for files under certain path substrings.
|
|
179
|
+
# Keys are path fragments; values are arrays of checker names.
|
|
180
|
+
# This is useful to avoid false positives in test/spec trees where
|
|
181
|
+
# dummy passwords and tokens are intentional.
|
|
182
|
+
#
|
|
183
|
+
# Default (built-in):
|
|
184
|
+
# { "spec" => %w[secrets], "test" => %w[secrets] }
|
|
185
|
+
#
|
|
186
|
+
# Override or extend:
|
|
187
|
+
Rails.application.config.guarddog.ignored_checks = {
|
|
188
|
+
"spec" => %w[secrets], # no secrets alerts in spec/
|
|
189
|
+
"test" => %w[secrets], # no secrets alerts in test/
|
|
190
|
+
"fixtures" => %w[secrets idor] # custom: also skip idor in fixtures
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Fail on severity level (for CI)
|
|
194
|
+
Rails.application.config.guarddog.fail_on_severity = :critical
|
|
195
|
+
|
|
196
|
+
# Strict mode (catch more issues, may have false positives)
|
|
197
|
+
Rails.application.config.guarddog.strict_mode = false
|
|
198
|
+
end
|
|
199
|
+
```
|
|
168
200
|
|
|
169
|
-
# Fail on severity level (for CI)
|
|
170
|
-
Rails.application.config.guarddog.fail_on_severity = :critical
|
|
171
201
|
|
|
172
|
-
|
|
173
|
-
Rails.application.config.guarddog.strict_mode = false
|
|
174
|
-
```
|
|
202
|
+
### Suppressing checks per directory
|
|
175
203
|
|
|
176
|
-
|
|
204
|
+
If you see false positives like dummy passwords flagged in test/spec files:
|
|
177
205
|
|
|
178
|
-
|
|
206
|
+
```
|
|
207
|
+
Secrets — Hardcoded secret detected
|
|
208
|
+
/app/spec/controllers/api/v1/users_controller_spec.rb:1975
|
|
209
|
+
Fix: Use ENV variables or Rails credentials
|
|
210
|
+
```
|
|
179
211
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
- **[Publishing Guide](PUBLISH_GUIDE.md)** - GitHub + RubyGems setup
|
|
212
|
+
GuardDog already silences `secrets` in `spec/` and `test/` by default. To add
|
|
213
|
+
more suppressions or override the defaults, set `ignored_checks` in your
|
|
214
|
+
initializer (see example above).
|
|
184
215
|
|
|
185
216
|
---
|
|
186
217
|
|
|
@@ -189,9 +220,7 @@ Rails.application.config.guarddog.strict_mode = false
|
|
|
189
220
|
### GitHub Actions
|
|
190
221
|
```yaml
|
|
191
222
|
name: Security Scan
|
|
192
|
-
|
|
193
223
|
on: [push, pull_request]
|
|
194
|
-
|
|
195
224
|
jobs:
|
|
196
225
|
guarddog:
|
|
197
226
|
runs-on: ubuntu-latest
|
|
@@ -203,122 +232,18 @@ jobs:
|
|
|
203
232
|
bundler-cache: true
|
|
204
233
|
- name: Run GuardDog
|
|
205
234
|
run: bundle exec rake guarddog:ci
|
|
206
|
-
- name: Upload report
|
|
207
|
-
if: always()
|
|
208
|
-
uses: actions/upload-artifact@v3
|
|
209
|
-
with:
|
|
210
|
-
name: guarddog-report
|
|
211
|
-
path: guarddog_report.*
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### GitLab CI
|
|
215
|
-
```yaml
|
|
216
|
-
security_scan:
|
|
217
|
-
image: ruby:3.2
|
|
218
|
-
script:
|
|
219
|
-
- bundle install
|
|
220
|
-
- bundle exec rake guarddog:ci
|
|
221
|
-
artifacts:
|
|
222
|
-
paths:
|
|
223
|
-
- guarddog_report.*
|
|
224
|
-
when: always
|
|
225
235
|
```
|
|
226
236
|
|
|
227
237
|
---
|
|
228
238
|
|
|
229
|
-
##
|
|
230
|
-
|
|
231
|
-
### 1. SQL Injection
|
|
232
|
-
```ruby
|
|
233
|
-
# ❌ DETECTED
|
|
234
|
-
User.where("id = #{params[:id]}")
|
|
235
|
-
User.find_by_sql("SELECT * FROM users WHERE id = #{id}")
|
|
236
|
-
|
|
237
|
-
# ✅ SAFE
|
|
238
|
-
User.where('id = ?', params[:id])
|
|
239
|
-
User.where(id: params[:id])
|
|
240
|
-
```
|
|
241
|
-
**CWE:** 89 | **OWASP:** A03:2021
|
|
242
|
-
|
|
243
|
-
### 2. XSS (Cross-Site Scripting)
|
|
244
|
-
```erb
|
|
245
|
-
<!-- ❌ DANGEROUS -->
|
|
246
|
-
<%= @user.bio %>
|
|
247
|
-
|
|
248
|
-
<!-- ✅ SAFE -->
|
|
249
|
-
<%= sanitize @user.bio %>
|
|
250
|
-
```
|
|
251
|
-
**CWE:** 79 | **OWASP:** A07:2021
|
|
252
|
-
|
|
253
|
-
### 3. CSRF (Cross-Site Request Forgery)
|
|
254
|
-
```ruby
|
|
255
|
-
# ❌ CRITICAL (without documented reason)
|
|
256
|
-
skip_before_action :verify_authenticity_token
|
|
257
|
-
|
|
258
|
-
# ✅ DOCUMENTED
|
|
259
|
-
# CSRF disabled for API endpoints
|
|
260
|
-
skip_before_action :verify_authenticity_token, if: :json_request?
|
|
261
|
-
```
|
|
262
|
-
**CWE:** 352 | **OWASP:** A01:2021
|
|
263
|
-
|
|
264
|
-
### 4. Mass Assignment
|
|
265
|
-
```ruby
|
|
266
|
-
# ❌ CRITICAL
|
|
267
|
-
params.permit!
|
|
268
|
-
|
|
269
|
-
# ✅ SAFE
|
|
270
|
-
params.require(:user).permit(:name, :email, :age)
|
|
271
|
-
```
|
|
272
|
-
**CWE:** 915 | **OWASP:** A01:2021
|
|
273
|
-
|
|
274
|
-
### 5. Hardcoded Secrets
|
|
275
|
-
```ruby
|
|
276
|
-
# ❌ CRITICAL
|
|
277
|
-
API_KEY = "sk_live_abc123def456"
|
|
278
|
-
|
|
279
|
-
# ✅ SAFE
|
|
280
|
-
ENV['API_KEY']
|
|
281
|
-
Rails.application.credentials.api_key
|
|
282
|
-
```
|
|
283
|
-
**CWE:** 798 | **OWASP:** A02:2021
|
|
284
|
-
|
|
285
|
-
### 6. DoS/ReDoS
|
|
286
|
-
```ruby
|
|
287
|
-
# ❌ HIGH RISK
|
|
288
|
-
User.all
|
|
289
|
-
/(a|a)*$/.match?('aaaa')
|
|
290
|
-
|
|
291
|
-
# ✅ SAFE
|
|
292
|
-
User.limit(100)
|
|
293
|
-
/^a+$/.match?('aaaa')
|
|
294
|
-
```
|
|
295
|
-
**CWE:** 400, 1333 | **OWASP:** A05:2021
|
|
296
|
-
|
|
297
|
-
### 7. IDOR
|
|
298
|
-
```ruby
|
|
299
|
-
# ❌ CRITICAL
|
|
300
|
-
@post = Post.find(params[:id])
|
|
301
|
-
|
|
302
|
-
# ✅ SAFE
|
|
303
|
-
@post = current_user.posts.find(params[:id])
|
|
304
|
-
authorize @post
|
|
305
|
-
```
|
|
306
|
-
**CWE:** 639 | **OWASP:** A01:2021
|
|
239
|
+
## 📈 What's New in v0.1.8
|
|
307
240
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
# ✅ SAFE
|
|
316
|
-
prompt = "Summarize: #{sanitize(params[:text]).first(500)}"
|
|
317
|
-
response = client.messages.create(
|
|
318
|
-
messages: [{ role: "user", content: prompt }]
|
|
319
|
-
)
|
|
320
|
-
```
|
|
321
|
-
**CWE:** 94 | **OWASP:** A03:2025
|
|
241
|
+
✨ Enhanced AI/LLM Injection Detection
|
|
242
|
+
✨ Improved Supply Chain Analysis
|
|
243
|
+
✨ Expanded DoS/ReDoS Patterns
|
|
244
|
+
✨ 40% Faster AST Analysis
|
|
245
|
+
✨ Better HTML Report
|
|
246
|
+
🎯 5 Critical Bug Fixes
|
|
322
247
|
|
|
323
248
|
---
|
|
324
249
|
|
|
@@ -335,20 +260,13 @@ Like a good guard dog, Rails GuardDog protects your application:
|
|
|
335
260
|
|
|
336
261
|
## 🤝 Contributing
|
|
337
262
|
|
|
338
|
-
Contributions welcome!
|
|
339
|
-
- Additional security checkers
|
|
340
|
-
- Performance optimizations
|
|
341
|
-
- More language support
|
|
342
|
-
- Advanced AST analysis
|
|
343
|
-
- Machine learning pattern detection
|
|
344
|
-
|
|
345
|
-
[GitHub Issues](https://github.com/sghani001/rails-guarddog/issues) | [GitHub Discussions](https://github.com/sghani001/rails-guarddog/discussions)
|
|
263
|
+
Contributions welcome! [GitHub Issues](https://github.com/sghani001/rails-guarddog/issues) | [GitHub Discussions](https://github.com/sghani001/rails-guarddog/discussions)
|
|
346
264
|
|
|
347
265
|
---
|
|
348
266
|
|
|
349
267
|
## 📄 License
|
|
350
268
|
|
|
351
|
-
MIT License - Free to use and modify.
|
|
269
|
+
MIT License - Free to use and modify.
|
|
352
270
|
|
|
353
271
|
---
|
|
354
272
|
|
|
@@ -357,8 +275,10 @@ MIT License - Free to use and modify. See [LICENSE](LICENSE) for details.
|
|
|
357
275
|
- **RubyGems:** https://rubygems.org/gems/rails-guarddog
|
|
358
276
|
- **GitHub:** https://github.com/sghani001/rails-guarddog
|
|
359
277
|
- **Issues:** https://github.com/sghani001/rails-guarddog/issues
|
|
360
|
-
- **
|
|
278
|
+
- **Releases:** https://github.com/sghani001/rails-guarddog/releases
|
|
361
279
|
|
|
362
280
|
---
|
|
363
281
|
|
|
282
|
+
**Rails GuardDog v0.1.8 — Production Ready**
|
|
283
|
+
|
|
364
284
|
*Beyond brakeman. Detect what others miss.* 🐕🔒
|
|
@@ -1,36 +1,73 @@
|
|
|
1
|
-
module Rails
|
|
2
|
-
module Guarddog
|
|
3
|
-
module Checkers
|
|
4
|
-
class BaseChecker
|
|
5
|
-
attr_accessor :findings
|
|
6
|
-
|
|
7
|
-
def initialize(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
module Rails
|
|
2
|
+
module Guarddog
|
|
3
|
+
module Checkers
|
|
4
|
+
class BaseChecker
|
|
5
|
+
attr_accessor :findings
|
|
6
|
+
|
|
7
|
+
def initialize(configuration = nil)
|
|
8
|
+
if configuration.is_a?(Configuration)
|
|
9
|
+
@configuration = configuration
|
|
10
|
+
@root = configuration.root
|
|
11
|
+
else
|
|
12
|
+
# Backwards-compatibility: a plain root string was passed
|
|
13
|
+
@root = configuration || Rails.root.to_s
|
|
14
|
+
@configuration = nil
|
|
15
|
+
end
|
|
16
|
+
@findings = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
raise NotImplementedError, "Subclasses must implement run"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
|
|
25
|
+
def add_finding(severity:, message:, file:, line:, snippet: "", remediation: "")
|
|
26
|
+
return if file_ignored_for_checker?(file)
|
|
27
|
+
|
|
28
|
+
findings << Finding.new(
|
|
29
|
+
severity: severity,
|
|
30
|
+
category: self.class.name.demodulize.gsub(/Checker$/, ''),
|
|
31
|
+
message: message,
|
|
32
|
+
file: file,
|
|
33
|
+
line: line,
|
|
34
|
+
code_snippet: snippet,
|
|
35
|
+
remediation: remediation
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns true when this checker should be silenced for the given file
|
|
40
|
+
# based on the `ignored_checks` configuration map.
|
|
41
|
+
def file_ignored_for_checker?(file)
|
|
42
|
+
return false unless @configuration
|
|
43
|
+
|
|
44
|
+
ignored = @configuration.ignored_checks || {}
|
|
45
|
+
name = checker_identifier
|
|
46
|
+
|
|
47
|
+
ignored.any? do |path_pattern, checker_names|
|
|
48
|
+
file.include?(path_pattern.to_s) &&
|
|
49
|
+
checker_names.map(&:to_s).include?(name)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Snake-case identifier that matches the names used in enabled_checkers /
|
|
54
|
+
# ignored_checks (e.g. "secrets", "sql_injection", "mass_assignment").
|
|
55
|
+
def checker_identifier
|
|
56
|
+
self.class.name
|
|
57
|
+
.demodulize
|
|
58
|
+
.gsub(/Checker$/, '')
|
|
59
|
+
.gsub(/([A-Z])(?=[A-Z][a-z])|([a-z\d])([A-Z])/) { "#{$1 || $2}_#{$3}" }
|
|
60
|
+
.downcase
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def glob_files(pattern)
|
|
64
|
+
excluded = @configuration&.excluded_paths || []
|
|
65
|
+
Dir.glob(File.join(@root, pattern)).reject do |file|
|
|
66
|
+
excluded.any? { |path| file.include?(path) }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
module Rails
|
|
2
|
-
module Guarddog
|
|
3
|
-
module Checkers
|
|
4
|
-
class SecretsChecker < BaseChecker
|
|
5
|
-
PATTERNS = [
|
|
6
|
-
/api[_-]?key\s*[=:]\s*['"][^'"]+['"]/i,
|
|
7
|
-
/secret[_-]?key\s*[=:]\s*['"][^'"]+['"]/i,
|
|
8
|
-
/password\s*[=:]\s*['"][^'"]+['"]/i,
|
|
9
|
-
/token\s*[=:]\s*['"][^'"]+['"]/i
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
def run
|
|
13
|
-
%w[*.rb *.yml .env .env.local].each do |pattern|
|
|
14
|
-
glob_files("**/{#{pattern}}").each do |file|
|
|
15
|
-
|
|
16
|
-
content
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
end
|
|
1
|
+
module Rails
|
|
2
|
+
module Guarddog
|
|
3
|
+
module Checkers
|
|
4
|
+
class SecretsChecker < BaseChecker
|
|
5
|
+
PATTERNS = [
|
|
6
|
+
/api[_-]?key\s*[=:]\s*['"][^'"]+['"]/i,
|
|
7
|
+
/secret[_-]?key\s*[=:]\s*['"][^'"]+['"]/i,
|
|
8
|
+
/password\s*[=:]\s*['"][^'"]+['"]/i,
|
|
9
|
+
/token\s*[=:]\s*['"][^'"]+['"]/i
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
%w[*.rb *.yml .env .env.local].each do |pattern|
|
|
14
|
+
glob_files("**/{#{pattern}}").each do |file|
|
|
15
|
+
content = File.read(file) rescue next
|
|
16
|
+
content.each_line.with_index do |line, idx|
|
|
17
|
+
PATTERNS.each do |pattern|
|
|
18
|
+
if line.match?(pattern) && !line.strip.start_with?('#')
|
|
19
|
+
add_finding(
|
|
20
|
+
severity: :critical,
|
|
21
|
+
message: "Hardcoded secret detected",
|
|
22
|
+
file: file,
|
|
23
|
+
line: idx + 1,
|
|
24
|
+
remediation: "Use ENV variables or Rails credentials"
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
findings
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
module Rails
|
|
2
|
-
module Guarddog
|
|
3
|
-
class Configuration
|
|
4
|
-
attr_writer :root
|
|
5
|
-
attr_accessor :enabled_checkers, :excluded_paths, :output_format
|
|
6
|
-
|
|
7
|
-
def initialize
|
|
8
|
-
@root = nil
|
|
9
|
-
@enabled_checkers = all_checkers
|
|
10
|
-
@excluded_paths = %w[vendor
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
module Rails
|
|
2
|
+
module Guarddog
|
|
3
|
+
class Configuration
|
|
4
|
+
attr_writer :root
|
|
5
|
+
attr_accessor :enabled_checkers, :excluded_paths, :output_format, :ignored_checks
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@root = nil
|
|
9
|
+
@enabled_checkers = all_checkers
|
|
10
|
+
@excluded_paths = %w[vendor node_modules]
|
|
11
|
+
# Per-directory checker suppression: keys are path substrings, values are
|
|
12
|
+
# arrays of checker names (same format as enabled_checkers).
|
|
13
|
+
# Defaults suppress the `secrets` checker inside spec/test trees because
|
|
14
|
+
# dummy passwords in test fixtures are intentional and not a real risk.
|
|
15
|
+
@ignored_checks = {
|
|
16
|
+
"spec" => %w[secrets],
|
|
17
|
+
"test" => %w[secrets]
|
|
18
|
+
}
|
|
19
|
+
@output_format = :console
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def root
|
|
23
|
+
@root || Rails.root.to_s
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def all_checkers
|
|
27
|
+
%w[
|
|
28
|
+
sql_injection xss csrf mass_assignment open_redirect secrets
|
|
29
|
+
dos idor ai_injection rate_limit dependency graphql
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
26
34
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
module Rails
|
|
2
|
-
module Guarddog
|
|
3
|
-
VERSION = "0.1.
|
|
4
|
-
end
|
|
5
|
-
end
|
|
1
|
+
module Rails
|
|
2
|
+
module Guarddog
|
|
3
|
+
VERSION = "0.1.9"
|
|
4
|
+
end
|
|
5
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-guarddog
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Security Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|