A comprehensive 8-stage vulnerability discovery audit was conducted against the ShopDB manufacturing asset management system using the Glasswing methodology (Recon, Hunt, Validate, Gapfill, Dedupe, Trace, Feedback, Report). The audit discovered 7 confirmed exploitable vulnerabilities across authentication, authorization, cryptography, and resource management domains.
| Severity | Count | Risk Level |
|---|---|---|
| HIGH | 3 | Critical attention required |
| MEDIUM | 3 | Important but lower priority |
| LOW | 1 | Informational |
The agent binary upload endpoint accepts ANY Windows PE executable without code signing or publisher verification. A compromised operator with endpoints.agentpackage + endpoints.agentupdate permissions can upload and deploy malicious binaries that execute as SYSTEM across the entire Windows endpoint fleet.
plugins/endpoints/api/agentupload.py:127-131
def looks_like_pe(data):
"""Whether data begins with the Windows PE 'MZ' magic."""
return len(data) >= 2 and data[:2] == _PE_MAGIC
The login endpoint leaks valid usernames through observable HTTP status code and message differences. Locked accounts return HTTP 403 "Account is locked", while invalid usernames return HTTP 401 "Invalid username or password".
shopdb/core/api/auth.py:102-107
Collector API key authentication uses Python's == operator for string comparison instead of constant-time comparison (hmac.compare_digest). This allows byte-by-byte extraction of COLLECTOR_API_KEY via timing side-channel attacks.
shopdb/core/api/collector.py:135-137
# Line 135 - Non-constant-time comparison
if expected_key and api_key == expected_key \
and not _env_fallback_disabled(pluginname):
return None
# setup.py:65, usb plugin, endpoints plugin
if hmac.compare_digest(expected, provided):
# Constant-time comparison
import hmac
# Replace line 135 with:
if expected_key and hmac.compare_digest(api_key, expected_key) \
and not _env_fallback_disabled(pluginname):
return None
The /refresh endpoint does not rotate refresh tokens when issuing new access tokens. A compromised refresh token remains valid for 30 days and can be reused unlimited times.
shopdb/core/api/auth.py:160-186
The /api/auth/refresh endpoint lacks rate limiting. In contrast, /api/auth/login implements fixed-window rate limiting (30 req/5min). Successfully executed 100 token refresh requests in 3.8 seconds (26.3 req/s).
shopdb/core/api/auth.py:160-186
# Add rate limiting decorator
@auth_bp.route('/refresh', methods=['POST'])
@limiter.limit("10 per minute")
@jwt_required(refresh=True)
def refresh():
...
File upload endpoints lack rate limiting. An authenticated user with upload permissions can repeatedly upload large files (up to 256MB per request) without throttling.
shopdb/config.py:145-151
from flask_limiter import Limiter
@upload_bp.before_request
@limiter.limit("10 per hour")
def rate_limit_uploads():
pass
Event deduplication check-then-insert (TOCTOU) race allows duplicate EndpointEvent records. Concurrent collector POSTs can both bypass the deduplication check, causing IntegrityError that aborts the entire transaction and loses ALL telemetry in the batch.
plugins/endpoints/plugin.py:1259-1278
# Option 1: Row-level locking
rows = db.session.query(...)
.with_for_update() # Acquire row locks
.all()
# Option 2: PostgreSQL ON CONFLICT
INSERT INTO endpointevent (...) VALUES (...)
ON CONFLICT (assetid, eventchannel, eventrecordid) DO NOTHING;
| Timeline | Vulnerability | Action |
|---|---|---|
| Week 1 (Immediate) |
#1: Agent Binary Injection | Implement Authenticode signature verification |
| Week 1 (Immediate) |
#2: Account Enumeration | Fix constant-time responses (always 401) |
| Week 1 (Immediate) |
#3: Timing Attack | Replace == with hmac.compare_digest() |
| Weeks 2-4 (Short-term) |
#5: Rate Limit Bypass | Add rate limiting to /refresh endpoint |
| Weeks 2-4 (Short-term) |
#4: Token Non-Rotation | Implement refresh token rotation |
| Weeks 2-4 (Short-term) |
#6: Upload DoS | Add rate limiting to upload endpoints |
| Month 2+ (Long-term) |
#7: Race Condition | Implement SELECT FOR UPDATE or ON CONFLICT |
Each finding was challenged by a second AI agent attempting to disprove it. Only 19% of initial findings survived validation (7 confirmed, 29 rejected as false positives). This high rejection rate demonstrates the effectiveness of adversarial validation in eliminating false positives.