Gate Detection for Reachability Scoring
Sprint: SPRINT_3405_0001_0001 Module: Scanner Reachability / Signals
Audience: Scanner and Signals contributors working on reachability scoring, and policy authors interpreting gated scores.
Overview
Gate detection identifies protective controls on code paths that reduce the likelihood of vulnerability exploitation. When a vulnerable function is guarded by authentication, a feature flag, an admin-only check, or a configuration gate, Stella Ops reduces its reachability score proportionally — so a reachable-but-gated path ranks below a reachable-and-open one.
Gate Types
| Gate Type | Multiplier | Description |
|---|---|---|
AuthRequired | 30% | Code path requires authentication |
FeatureFlag | 20% | Code path behind a feature flag |
AdminOnly | 15% | Code path requires admin/elevated role |
NonDefaultConfig | 50% | Code path requires non-default configuration |
Multiplier Stacking
Multiple gate types stack multiplicatively:
Auth (30%) × Feature Flag (20%) = 6%
Auth (30%) × Admin (15%) = 4.5%
All four gates = ~0.45% (floored to 5%)
A minimum floor of 5% prevents scores from reaching zero.
Detection Methods
AuthGateDetector
Detects authentication requirements:
C# Patterns:
[Authorize]attributeUser.Identity.IsAuthenticatedchecksHttpContext.Useraccess- JWT/Bearer token validation
Java Patterns:
@PreAuthorize,@SecuredannotationsSecurityContextHolder.getContext()- Spring Security filter chains
Go Patterns:
- Middleware patterns (
authMiddleware,RequireAuth) - Context-based auth checks
JavaScript/TypeScript Patterns:
- Express.js
passportmiddleware - JWT verification middleware
- Session checks
FeatureFlagDetector
Detects feature flag guards:
Patterns:
- LaunchDarkly:
ldClient.variation(),ld.boolVariation() - Split.io:
splitClient.getTreatment() - Unleash:
unleash.isEnabled() - Custom:
featureFlags.isEnabled(),isFeatureEnabled()
When a supported invocation or decorator uses an immediate quoted literal as its first argument, that flag key is retained in DetectedGate.detail. Dynamic flag expressions remain a generic feature-flag gate; the detector does not infer identity from unrelated quoted strings later in the source window.
AdminOnlyDetector
Detects admin/role requirements:
Patterns:
[Authorize(Roles = "Admin")]User.IsInRole("Admin")@RolesAllowed("ADMIN")- RBAC middleware checks
ConfigGateDetector
Detects configuration-based gates:
Patterns:
- Environment variable checks (
process.env.ENABLE_FEATURE) - Configuration file conditionals
- Runtime feature toggles
- Debug-only code paths
Output Contract
DetectedGate
Note: In Signals API outputs, type is serialized as the C# enum name (e.g., "AuthRequired"). In richgraph-v1 JSON, type is lowerCamelCase and gate fields are snake_case (see example below).
interface DetectedGate {
type: 'AuthRequired' | 'FeatureFlag' | 'AdminOnly' | 'NonDefaultConfig';
detail: string; // Human-readable description
guardSymbol: string; // Symbol where gate was detected
sourceFile?: string; // Source file location
lineNumber?: number; // Line number
confidence: number; // 0.0-1.0 confidence score
detectionMethod: string; // Detection algorithm used
}
GateDetectionResult
interface GateDetectionResult {
gates: DetectedGate[];
hasGates: boolean;
primaryGate?: DetectedGate; // Highest confidence gate
combinedMultiplierBps: number; // Basis points (10000 = 100%)
}
Integration
RichGraph Edge Annotation
Gates are annotated on RichGraphEdge objects:
public sealed record RichGraphEdge
{
// ... existing properties ...
/// <summary>Gates detected on this edge</summary>
public IReadOnlyList<DetectedGate> Gates { get; init; } = [];
/// <summary>Combined gate multiplier in basis points</summary>
public int GateMultiplierBps { get; init; } = 10000;
}
richgraph-v1 JSON example (edge fragment):
{
"gate_multiplier_bps": 3000,
"gates": [
{
"type": "authRequired",
"detail": "[Authorize] attribute on controller",
"guard_symbol": "MyController.VulnerableAction",
"source_file": "src/MyController.cs",
"line_number": 42,
"detection_method": "csharp.attribute",
"confidence": 0.95
}
]
}
ReachabilityReport
Gates are included in the reachability report:
{
"vulnId": "CVE-2024-0001",
"reachable": true,
"score": 7.5,
"adjustedScore": 2.25,
"gates": [
{
"type": "AuthRequired",
"detail": "[Authorize] attribute on controller",
"guardSymbol": "MyController.VulnerableAction",
"confidence": 0.95
}
],
"gateMultiplierBps": 3000
}
Configuration
appsettings.json
{
"Reachability": {
"GateMultipliers": {
"AuthRequiredMultiplierBps": 3000,
"FeatureFlagMultiplierBps": 2000,
"AdminOnlyMultiplierBps": 1500,
"NonDefaultConfigMultiplierBps": 5000,
"MinimumMultiplierBps": 500
}
}
}
Metrics
| Metric | Description |
|---|---|
scanner.gates_detected_total | Total gates detected by type |
scanner.gate_reduction_applied | Histogram of multiplier reductions |
scanner.gated_vulns_total | Vulnerabilities with gates detected |
Related Documentation
- Scanner Architecture
- Signals Service Architecture
- Reachability Lattice — how gated scores feed lattice state and confidence.
- Determinism & Reproducibility Technical Reference (14-Dec-2025 advisory), sections 2.2 and 4.3.
