- Implemented PathViewerComponent for visualizing reachability call paths. - Added RiskDriftCardComponent to display reachability drift results. - Created corresponding HTML templates and SCSS styles for both components. - Introduced test fixtures for reachability analysis in JSON format. - Enhanced user interaction with collapsible and expandable features in PathViewer. - Included risk trend visualization and summary metrics in RiskDriftCard.
257 lines
7.6 KiB
Markdown
257 lines
7.6 KiB
Markdown
# Vuln Surface Contract v1
|
|
|
|
**Sprint:** SPRINT_3700_0002_0001
|
|
**Task:** SURF-024
|
|
**Schema:** `stella.ops/vulnSurface@v1`
|
|
|
|
## Overview
|
|
|
|
A Vulnerability Surface represents the specific methods that changed between a vulnerable and fixed version of a package. This enables precise reachability analysis by identifying the exact "trigger" methods that are dangerous rather than treating the entire package as vulnerable.
|
|
|
|
## Use Cases
|
|
|
|
1. **Noise Reduction** - Only flag findings where code actually calls vulnerable methods
|
|
2. **Confidence Tiers** - "Confirmed reachable" (calls trigger) vs "Potentially reachable" (uses package)
|
|
3. **Remediation Guidance** - Show developers exactly which API calls to avoid
|
|
4. **VEX Precision** - Automatically generate VEX "not_affected" for unreachable triggers
|
|
|
|
## Data Model
|
|
|
|
### VulnSurface
|
|
|
|
Root object representing a computed vulnerability surface.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `surface_id` | integer | Yes | Database ID |
|
|
| `cve_id` | string | Yes | CVE identifier (e.g., "CVE-2024-12345") |
|
|
| `package_id` | string | Yes | Package identifier in PURL format |
|
|
| `ecosystem` | string | Yes | Package ecosystem: `nuget`, `npm`, `maven`, `pypi` |
|
|
| `vuln_version` | string | Yes | Vulnerable version analyzed |
|
|
| `fixed_version` | string | Yes | First fixed version used for diff |
|
|
| `sinks` | VulnSurfaceSink[] | Yes | Changed methods (vulnerability triggers) |
|
|
| `trigger_count` | integer | Yes | Number of callers to sink methods |
|
|
| `status` | VulnSurfaceStatus | Yes | Computation status |
|
|
| `confidence` | number | Yes | Confidence score (0.0-1.0) |
|
|
| `computed_at` | string | Yes | ISO 8601 timestamp |
|
|
|
|
### VulnSurfaceSink
|
|
|
|
A method that changed between vulnerable and fixed versions.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `sink_id` | integer | Yes | Database ID |
|
|
| `method_key` | string | Yes | Fully qualified method signature |
|
|
| `method_name` | string | Yes | Simple method name |
|
|
| `declaring_type` | string | Yes | Containing class/module |
|
|
| `namespace` | string | No | Namespace/package |
|
|
| `change_type` | MethodChangeType | Yes | How the method changed |
|
|
| `is_public` | boolean | Yes | Whether method is publicly accessible |
|
|
| `parameter_count` | integer | No | Number of parameters |
|
|
| `return_type` | string | No | Return type |
|
|
| `source_file` | string | No | Source file (from debug symbols) |
|
|
| `start_line` | integer | No | Starting line number |
|
|
| `end_line` | integer | No | Ending line number |
|
|
|
|
### VulnSurfaceTrigger
|
|
|
|
A call site that invokes a vulnerable sink method.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `trigger_id` | integer | Yes | Database ID |
|
|
| `sink_id` | integer | Yes | Reference to sink |
|
|
| `scan_id` | UUID | Yes | Scan where trigger was found |
|
|
| `caller_node_id` | string | Yes | Call graph node ID |
|
|
| `caller_method_key` | string | Yes | FQN of calling method |
|
|
| `caller_file` | string | No | Source file of caller |
|
|
| `caller_line` | integer | No | Line number of call |
|
|
| `reachability_bucket` | string | Yes | Reachability classification |
|
|
| `path_length` | integer | No | Shortest path from entrypoint |
|
|
| `confidence` | number | Yes | Confidence score (0.0-1.0) |
|
|
| `call_type` | string | Yes | Call type: `direct`, `virtual`, `interface`, `reflection` |
|
|
| `is_conditional` | boolean | Yes | Whether call is behind a condition |
|
|
|
|
## Enums
|
|
|
|
### VulnSurfaceStatus
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `pending` | Surface computation queued |
|
|
| `computing` | Currently being computed |
|
|
| `computed` | Successfully computed |
|
|
| `failed` | Computation failed |
|
|
| `stale` | Needs recomputation (new version available) |
|
|
|
|
### MethodChangeType
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `added` | Method added in fix (not in vulnerable version) |
|
|
| `removed` | Method removed in fix (was in vulnerable version) |
|
|
| `modified` | Method body changed between versions |
|
|
| `unknown` | Change type could not be determined |
|
|
|
|
### Reachability Buckets
|
|
|
|
| Bucket | Description | Risk Level |
|
|
|--------|-------------|------------|
|
|
| `entrypoint` | Sink is directly exposed as entrypoint | Critical |
|
|
| `direct` | Reachable from entrypoint with no authentication gates | High |
|
|
| `runtime` | Reachable but behind runtime conditions/auth | Medium |
|
|
| `unknown` | Reachability could not be determined | Medium |
|
|
| `unreachable` | No path from any entrypoint | Low |
|
|
|
|
## Fingerprinting Methods
|
|
|
|
### cecil-il (NuGet/.NET)
|
|
|
|
Uses Mono.Cecil to compute SHA-256 hash of IL instruction sequence:
|
|
|
|
```
|
|
IL_0000: ldarg.0
|
|
IL_0001: call System.Object::.ctor()
|
|
IL_0006: ret
|
|
```
|
|
|
|
Normalized to remove:
|
|
- NOP instructions
|
|
- Debug sequence points
|
|
- Local variable indices (replaced with placeholders)
|
|
|
|
### babel-ast (npm/Node.js)
|
|
|
|
Uses Babel to parse JavaScript/TypeScript and compute hash of normalized AST:
|
|
|
|
```javascript
|
|
function vulnerable(input) {
|
|
eval(input); // dangerous!
|
|
}
|
|
```
|
|
|
|
Normalized to remove:
|
|
- Comments
|
|
- Whitespace
|
|
- Variable names (renamed to positional)
|
|
|
|
### asm-bytecode (Maven/Java)
|
|
|
|
Uses ASM to compute hash of Java bytecode:
|
|
|
|
```
|
|
ALOAD 0
|
|
INVOKESPECIAL java/lang/Object.<init>()V
|
|
RETURN
|
|
```
|
|
|
|
Normalized to remove:
|
|
- Line number tables
|
|
- Local variable tables
|
|
- Stack map frames
|
|
|
|
### python-ast (PyPI)
|
|
|
|
Uses Python's `ast` module to compute hash of normalized AST:
|
|
|
|
```python
|
|
def vulnerable(user_input):
|
|
exec(user_input) # dangerous!
|
|
```
|
|
|
|
Normalized to remove:
|
|
- Docstrings
|
|
- Comments
|
|
- Variable names
|
|
|
|
## Database Schema
|
|
|
|
```sql
|
|
-- Surfaces table
|
|
CREATE TABLE scanner.vuln_surfaces (
|
|
id UUID PRIMARY KEY,
|
|
tenant_id UUID NOT NULL,
|
|
cve_id TEXT NOT NULL,
|
|
package_ecosystem TEXT NOT NULL,
|
|
package_name TEXT NOT NULL,
|
|
vuln_version TEXT NOT NULL,
|
|
fixed_version TEXT,
|
|
fingerprint_method TEXT NOT NULL,
|
|
total_methods_vuln INTEGER,
|
|
total_methods_fixed INTEGER,
|
|
changed_method_count INTEGER,
|
|
computed_at TIMESTAMPTZ DEFAULT now(),
|
|
UNIQUE (tenant_id, cve_id, package_ecosystem, package_name, vuln_version)
|
|
);
|
|
|
|
-- Sinks table
|
|
CREATE TABLE scanner.vuln_surface_sinks (
|
|
id UUID PRIMARY KEY,
|
|
surface_id UUID REFERENCES scanner.vuln_surfaces(id) ON DELETE CASCADE,
|
|
method_key TEXT NOT NULL,
|
|
method_name TEXT NOT NULL,
|
|
declaring_type TEXT NOT NULL,
|
|
change_type TEXT NOT NULL,
|
|
UNIQUE (surface_id, method_key)
|
|
);
|
|
|
|
-- Triggers table
|
|
CREATE TABLE scanner.vuln_surface_triggers (
|
|
id UUID PRIMARY KEY,
|
|
sink_id UUID REFERENCES scanner.vuln_surface_sinks(id) ON DELETE CASCADE,
|
|
scan_id UUID NOT NULL,
|
|
caller_node_id TEXT NOT NULL,
|
|
reachability_bucket TEXT NOT NULL,
|
|
confidence REAL NOT NULL,
|
|
UNIQUE (sink_id, scan_id, caller_node_id)
|
|
);
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### POST /api/v1/surfaces/compute
|
|
|
|
Request surface computation for a CVE + package.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"cveId": "CVE-2024-12345",
|
|
"ecosystem": "nuget",
|
|
"packageName": "Newtonsoft.Json",
|
|
"vulnVersion": "13.0.1",
|
|
"fixedVersion": "13.0.2"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"surfaceId": "uuid",
|
|
"status": "pending"
|
|
}
|
|
```
|
|
|
|
### GET /api/v1/surfaces/{surfaceId}
|
|
|
|
Get computed surface with sinks.
|
|
|
|
### GET /api/v1/surfaces/{surfaceId}/triggers?scanId={scanId}
|
|
|
|
Get triggers for a surface in a specific scan.
|
|
|
|
## Integration Points
|
|
|
|
1. **Concelier** - Feeds CVE + affected version ranges
|
|
2. **Scanner** - Computes surfaces during SBOM analysis
|
|
3. **Call Graph** - Provides reachability analysis
|
|
4. **VEX Lens** - Uses surfaces for automated VEX decisions
|
|
5. **UI** - Displays surface details and trigger paths
|
|
|
|
## References
|
|
|
|
- [Vuln Surfaces Sprint](../implplan/SPRINT_3700_0002_0001_vuln_surfaces_core.md)
|
|
- [Reachability Architecture](../reachability/README.md)
|
|
- [RichGraph Contract](./richgraph-v1.md)
|