nemesis-shield 0.1.2 → 0.1.3
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 +5 -5
- data/nemesis_shield.rb +15 -4
- data/nemesis_shield_llm.rb +4 -4
- 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: da20881bfecc4f9a945ef918909095b94f6b1174cf42461ac141cc36eedc4aef
|
|
4
|
+
data.tar.gz: '059fe7b53dadcffbe69aac805359ef11ee61884bdeb5ccacbfb633f2d95564f5'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7c658daadf73fc9f2d6a70dbf0ff13ecdcd852561d88035f68a403e285e0850245a04f4094f5c6f50c1ea9330acd0371015bccaa9748cc5da2c7efd62f47411
|
|
7
|
+
data.tar.gz: 1d5b523c7a56a3a9f66b54294c1e4bf85aba7b51ba8ff8bbdbc9c832d5051abfa4e8b786af0d9685e021fcc79144ac4e29b05b76855a5222266f53df5e6aa458
|
data/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Nemesis Shield
|
|
1
|
+
# Nemesis Shield - Ruby
|
|
2
2
|
|
|
3
3
|
Native Ruby SDK for [Nemesis Shield](https://shield.nemesislabs.xyz). Learns your app's normal
|
|
4
4
|
behavior; in **enforce mode BLOCKS off-baseline requests** (auth bypass, path traversal, scanners,
|
|
5
5
|
unusual methods) before your app runs. One Rack middleware works with **Rails, Sinatra and any Rack
|
|
6
6
|
app**. Positive-security, fail-open, privacy-preserving.
|
|
7
7
|
|
|
8
|
-
**Rails**
|
|
8
|
+
**Rails** - `config/application.rb`:
|
|
9
9
|
```ruby
|
|
10
10
|
require "nemesis_shield"
|
|
11
11
|
config.middleware.use NemesisShield::Middleware, token: ENV["NEMESIS_TOKEN"]
|
|
@@ -31,7 +31,7 @@ attacks blocked (403).
|
|
|
31
31
|
|
|
32
32
|
## LLM Guard (OWASP LLM Top 10)
|
|
33
33
|
|
|
34
|
-
The same HashLR ML classifier every Nemesis Shield SDK ships
|
|
34
|
+
The same HashLR ML classifier every Nemesis Shield SDK ships - catches obfuscated/paraphrased prompt
|
|
35
35
|
injection signature rules miss, scored identically in every language.
|
|
36
36
|
|
|
37
37
|
```ruby
|
|
@@ -47,7 +47,7 @@ Regex first, then ML. Blocks at ≥ 0.85 (high), flags at ≥ 0.45.
|
|
|
47
47
|
|
|
48
48
|
## Full coverage & safe-unlock
|
|
49
49
|
|
|
50
|
-
**Mount it first / outermost** so *every* route is inspected (not just API routes
|
|
50
|
+
**Mount it first / outermost** so *every* route is inspected (not just API routes - attackers hit any path):
|
|
51
51
|
|
|
52
52
|
```
|
|
53
53
|
use NemesisShield::Middleware, token: ENV["NEMESIS_TOKEN"] # top of the Rack stack
|
|
@@ -61,7 +61,7 @@ use NemesisShield::Middleware, token: ENV["NEMESIS_TOKEN"] # top of the Rack s
|
|
|
61
61
|
export NEMESIS_SHIELD_BOOTSTRAP="/login,/admin,/healthz"
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
**Verify coverage**
|
|
64
|
+
**Verify coverage** - in observe mode, hit a normal route, a param, and a scanner path, then confirm all three appear in the console (Activity / Behaviors):
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
67
|
curl -s "http://localhost:8080/" >/dev/null
|
data/nemesis_shield.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Nemesis Shield
|
|
1
|
+
# Nemesis Shield - Sentinel SDK for Ruby (native: local shape + policy cache + inline blocking).
|
|
2
2
|
# Learns your app's normal behavior; in enforce mode blocks off-baseline requests (auth bypass, path
|
|
3
|
-
# traversal, scanners, unusual methods) before your app runs. Works with any Rack app
|
|
3
|
+
# traversal, scanners, unusual methods) before your app runs. Works with any Rack app - Rails,
|
|
4
4
|
# Sinatra, Hanami, raw Rack. Fail-open, privacy-preserving.
|
|
5
5
|
#
|
|
6
6
|
# # Rails (config/application.rb): config.middleware.use NemesisShield::Middleware, token: ENV["NEMESIS_TOKEN"]
|
|
@@ -12,7 +12,7 @@ require "thread"
|
|
|
12
12
|
|
|
13
13
|
module NemesisShield
|
|
14
14
|
DEFAULT_ENDPOINT = "https://shield.nemesislabs.xyz/api/v1/sketches".freeze
|
|
15
|
-
# Canonical value taxonomy
|
|
15
|
+
# Canonical value taxonomy - must match the shared engine (tokenize.ts) byte-for-byte so a Ruby
|
|
16
16
|
# app and a Node/Python app produce identical shape hashes.
|
|
17
17
|
UUID = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
|
|
18
18
|
EMAIL = /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/
|
|
@@ -29,6 +29,11 @@ module NemesisShield
|
|
|
29
29
|
ALNUM = /\A[A-Za-z0-9]+\z/
|
|
30
30
|
# A run of 7+ letters => reads like a word / route name, not an opaque id/token.
|
|
31
31
|
WORD = /[A-Za-z]{7,}/
|
|
32
|
+
# A hostname path segment (network-zone routes like example.com, sub.example.co.uk) collapses to
|
|
33
|
+
# {domain}. Lookahead-free so it ports byte-identically to RE2 engines and matches the edge SDK.
|
|
34
|
+
DOMAIN = /\A([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,24}\z/i
|
|
35
|
+
# A digit, used to tell a generated composite id (inc_ip_1_2_3_4_178..) from a snake_case word.
|
|
36
|
+
DIGIT = /\d/
|
|
32
37
|
|
|
33
38
|
module_function
|
|
34
39
|
|
|
@@ -43,7 +48,13 @@ module NemesisShield
|
|
|
43
48
|
when "hex" then "{hex}"
|
|
44
49
|
when "base64" then "{token}"
|
|
45
50
|
when "alnum" then (seg.length >= 12 && seg !~ WORD) ? "{id}" : seg
|
|
46
|
-
else
|
|
51
|
+
else
|
|
52
|
+
# Hostnames collapse to {domain}; underscored generated ids that carry a digit (or are very
|
|
53
|
+
# long) collapse to {id}. Kebab route names (iso-27001) have no underscore, so stay literal.
|
|
54
|
+
if seg =~ DOMAIN then "{domain}"
|
|
55
|
+
elsif seg.include?("_") && (seg =~ DIGIT || seg.length >= 20) then "{id}"
|
|
56
|
+
else seg end
|
|
57
|
+
end
|
|
47
58
|
end.join("/")
|
|
48
59
|
out.empty? ? "/" : out
|
|
49
60
|
end
|
data/nemesis_shield_llm.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# LLM Guard for Ruby
|
|
1
|
+
# LLM Guard for Ruby - OWASP-LLM-Top-10 detection with the HashLR ML classifier shared across every
|
|
2
2
|
# Nemesis Shield SDK. Feature buckets are fnv1a(feature) % dim (the same hash used for HTTP sketches),
|
|
3
3
|
# so scores match every other language. Char n-grams over a canonicalized (de-leetspeaked, ASCII-alnum)
|
|
4
4
|
# form catch obfuscation the regex layer misses.
|
|
@@ -9,7 +9,7 @@ require_relative "nemesis_shield"
|
|
|
9
9
|
module NemesisShield
|
|
10
10
|
module LLM
|
|
11
11
|
MODEL = JSON.parse(File.read(File.join(__dir__, "ml_weights.json"))).freeze
|
|
12
|
-
DIM = MODEL["dim"] # feature space is fixed across versions
|
|
12
|
+
DIM = MODEL["dim"] # feature space is fixed across versions - only weights/bias/thresholds swap
|
|
13
13
|
# Swappable model state (module ivars so refresh_model can hot-swap a newer published version).
|
|
14
14
|
@bias = MODEL["bias"]
|
|
15
15
|
@weights = MODEL["weights"]
|
|
@@ -73,8 +73,8 @@ module NemesisShield
|
|
|
73
73
|
def verify_model_signature(raw, sig_b64)
|
|
74
74
|
require "openssl"
|
|
75
75
|
require "base64"
|
|
76
|
-
return true if MODEL_PUBLIC_KEY_HEX.empty? # no key pinned
|
|
77
|
-
return false if sig_b64.nil? || sig_b64.empty? # key pinned but bundle unsigned
|
|
76
|
+
return true if MODEL_PUBLIC_KEY_HEX.empty? # no key pinned - version gate + HTTPS apply
|
|
77
|
+
return false if sig_b64.nil? || sig_b64.empty? # key pinned but bundle unsigned - reject
|
|
78
78
|
pk = OpenSSL::PKey.new_raw_public_key("ED25519", [MODEL_PUBLIC_KEY_HEX].pack("H*"))
|
|
79
79
|
pk.verify(nil, Base64.strict_decode64(sig_b64), raw)
|
|
80
80
|
rescue StandardError
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nemesis-shield
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Autogon Inc.
|
|
@@ -48,6 +48,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
48
48
|
requirements: []
|
|
49
49
|
rubygems_version: 4.0.16
|
|
50
50
|
specification_version: 4
|
|
51
|
-
summary: Nemesis Shield
|
|
51
|
+
summary: Nemesis Shield - Sentinel SDK for Ruby (positive-security middleware + LLM
|
|
52
52
|
guard)
|
|
53
53
|
test_files: []
|