|
| 1 | +.. _reference_vulnerability_triage: |
| 2 | + |
| 3 | +Vulnerability Triage Engine |
| 4 | +=========================== |
| 5 | + |
| 6 | +DejaCode includes a **Vulnerability Triage Engine** that evaluates configurable |
| 7 | +detection rules against your product inventory and recommends a remediation action for |
| 8 | +each matched vulnerability. It provides a structured way to prioritize, track, and act |
| 9 | +on vulnerability exposure across your products. |
| 10 | + |
| 11 | +When a ruleset fires, DejaCode creates a **triage record** linking the vulnerability to |
| 12 | +the product and the ruleset that detected it. The record carries the recommended action, |
| 13 | +the detection date, the last evaluation date, and an optional link to a DejaCode request |
| 14 | +opened automatically by the engine. |
| 15 | + |
| 16 | +Rulesets are **disabled by default**. Each dataspace creates and configures the rulesets |
| 17 | +that are relevant to its security program via the **Admin** interface. |
| 18 | + |
| 19 | +1. Built-in Rules |
| 20 | +----------------- |
| 21 | + |
| 22 | +Seven rules are available out of the box. Each rule implements a specific detection |
| 23 | +condition evaluated against the vulnerabilities known to affect the product's packages. |
| 24 | + |
| 25 | +.. list-table:: |
| 26 | + :header-rows: 1 |
| 27 | + :widths: 28 72 |
| 28 | + |
| 29 | + * - Label |
| 30 | + - Description |
| 31 | + * - | **Risk Score** |
| 32 | + | ``risk_score`` |
| 33 | + - Detects vulnerabilities whose risk score is at or above the configured threshold. |
| 34 | + * - | **Weighted Risk** |
| 35 | + | ``weighted_risk`` |
| 36 | + - Detects vulnerabilities affecting at least one package whose weighted risk score |
| 37 | + meets the configured threshold. The weighted risk score combines the vulnerability |
| 38 | + risk with the package's exposure level in the product. |
| 39 | + * - | **Exploited Vulnerability** |
| 40 | + | ``exploited_vulnerability`` |
| 41 | + - Detects vulnerabilities for which a known active exploit is available |
| 42 | + (exploitability value equals 2.0). |
| 43 | + * - | **Reachable Vulnerability** |
| 44 | + | ``reachable_vulnerability`` |
| 45 | + - Detects vulnerabilities confirmed as reachable in the product context: at least |
| 46 | + one VulnerabilityAnalysis record for this vulnerability has ``is_reachable`` set |
| 47 | + to true. |
| 48 | + * - | **Unresolved Vulnerability** |
| 49 | + | ``unresolved_vulnerability`` |
| 50 | + - Detects vulnerabilities affecting the product where at least one package has no |
| 51 | + completed triage analysis (i.e., no analysis in a terminal state: resolved, |
| 52 | + resolved_with_pedigree, or not_affected). |
| 53 | + * - | **Stale Vulnerability** |
| 54 | + | ``stale_vulnerability`` |
| 55 | + - Detects high-risk vulnerabilities that have remained unaddressed beyond the |
| 56 | + configured number of days. Considers only vulnerabilities whose risk score meets |
| 57 | + or exceeds the configured minimum. |
| 58 | + * - | **Dev-Only Vulnerable Package** |
| 59 | + | ``dev_only_vulnerable_package`` |
| 60 | + - Detects vulnerabilities that exclusively affect packages marked as non-deployed |
| 61 | + in the product, indicating a lower exposure risk. |
| 62 | + |
| 63 | +.. seealso:: |
| 64 | + Refer to :ref:`reference_vulnerability_management` for background on vulnerability |
| 65 | + fields such as risk score and exploitability. |
| 66 | + |
| 67 | +1.1 Rule Parameters |
| 68 | +^^^^^^^^^^^^^^^^^^^ |
| 69 | + |
| 70 | +The following parameters are supported by rules that accept them: |
| 71 | + |
| 72 | +**Risk Score** (``risk_score``) |
| 73 | + |
| 74 | +- ``min_risk_score`` (float, 0.0-10.0): only flag vulnerabilities whose risk score is |
| 75 | + greater than or equal to this value. Defaults to ``8.0``. |
| 76 | + |
| 77 | +**Weighted Risk** (``weighted_risk``) |
| 78 | + |
| 79 | +- ``min_weighted_risk_score`` (float, 0.0-10.0): only flag vulnerabilities affecting a |
| 80 | + package whose weighted risk score is greater than or equal to this value. Defaults to |
| 81 | + ``8.0``. |
| 82 | + |
| 83 | +**Stale Vulnerability** (``stale_vulnerability``) |
| 84 | + |
| 85 | +- ``max_days`` (integer, min 1): maximum number of days a high-risk vulnerability may |
| 86 | + remain without a completed analysis before it is flagged. Defaults to ``30``. |
| 87 | +- ``min_risk_score`` (float, 0.0-10.0): only consider vulnerabilities whose risk score |
| 88 | + is greater than or equal to this value. Defaults to ``8.0``. |
| 89 | + |
| 90 | +2. Triage Actions |
| 91 | +----------------- |
| 92 | + |
| 93 | +Each ruleset recommends a single remediation action. The action is stored on every |
| 94 | +triage record created by that ruleset and displayed in the **Recommendation** column |
| 95 | +of the product Vulnerabilities tab. |
| 96 | + |
| 97 | +.. list-table:: |
| 98 | + :header-rows: 1 |
| 99 | + |
| 100 | + * - Action |
| 101 | + - Label |
| 102 | + * - ``upgrade`` |
| 103 | + - Upgrade Package |
| 104 | + * - ``apply_patch`` |
| 105 | + - Apply Patch |
| 106 | + * - ``forensic_analysis`` |
| 107 | + - Forensic Analysis |
| 108 | + * - ``reachability_analysis`` |
| 109 | + - Reachability Analysis |
| 110 | + * - ``change_config`` |
| 111 | + - Change Configuration |
| 112 | + * - ``replace_package`` |
| 113 | + - Replace Package |
| 114 | + * - ``notify`` |
| 115 | + - Notify |
| 116 | + * - ``create_request`` |
| 117 | + - Create DejaCode Request |
| 118 | + |
| 119 | +3. Triage Record Lifecycle |
| 120 | +-------------------------- |
| 121 | + |
| 122 | +A **triage record** is created per (vulnerability, product, ruleset) combination the |
| 123 | +first time a ruleset evaluation matches a vulnerability. Its lifecycle follows these |
| 124 | +states: |
| 125 | + |
| 126 | +- **Detected**: the record is created the first time the ruleset fires for the |
| 127 | + vulnerability. ``detected_date`` is set at this point and never changes on subsequent |
| 128 | + evaluations. |
| 129 | +- **Active**: the record is updated in place on each subsequent evaluation as long as |
| 130 | + the vulnerability still matches any active rule in the ruleset. ``last_checked`` is |
| 131 | + updated on every run. |
| 132 | +- **Deleted**: when a vulnerability no longer matches any rule in the ruleset, its |
| 133 | + triage record is deleted. Any preset-applied analysis for that vulnerability is also |
| 134 | + removed. If the conditions recur later, a new record is created with a fresh |
| 135 | + ``detected_date``. |
| 136 | + |
| 137 | +Only **active** triage records appear in the product Vulnerabilities tab. |
| 138 | + |
| 139 | +4. Configuration |
| 140 | +---------------- |
| 141 | + |
| 142 | +The triage engine is configured through **Triage Rulesets** in the Admin interface |
| 143 | +under :guilabel:`Vulnerabilities > Triage Rulesets`. |
| 144 | + |
| 145 | +.. seealso:: |
| 146 | + For step-by-step instructions on creating and configuring rulesets through the Admin |
| 147 | + UI, refer to :ref:`how_to_7`. |
| 148 | + |
| 149 | +4.1 Triage Ruleset |
| 150 | +^^^^^^^^^^^^^^^^^^ |
| 151 | + |
| 152 | +Each ruleset combines one or more detection rules with a single recommended action: |
| 153 | + |
| 154 | +.. list-table:: |
| 155 | + :header-rows: 1 |
| 156 | + |
| 157 | + * - Field |
| 158 | + - Description |
| 159 | + * - **Name** |
| 160 | + - A descriptive name for the ruleset (e.g., "Critical Vulnerabilities"). |
| 161 | + * - **Action** |
| 162 | + - The remediation action to recommend when the ruleset fires. |
| 163 | + * - **Precedence** |
| 164 | + - Integer controlling priority when multiple rulesets match the same vulnerability |
| 165 | + for the same product. The ruleset with the highest precedence value wins and its |
| 166 | + triage record is displayed. Unique per dataspace, so ties cannot occur. |
| 167 | + * - **Enabled** |
| 168 | + - When unchecked, the ruleset is excluded from all evaluations and its existing |
| 169 | + triage records are deleted immediately. Any preset-applied analysis is left in |
| 170 | + place: only the tracking record is removed, not the analysis itself. |
| 171 | + * - **Analysis Preset** |
| 172 | + - Optional. An AnalysisPreset whose default values are applied automatically to |
| 173 | + each matched vulnerability (see section 4.2). |
| 174 | + * - **Request Template** |
| 175 | + - Optional. A RequestTemplate of content type Product used to open a DejaCode |
| 176 | + request automatically for each new triage record (see section 4.3). |
| 177 | + |
| 178 | +4.2 Analysis Preset |
| 179 | +^^^^^^^^^^^^^^^^^^^ |
| 180 | + |
| 181 | +An **Analysis Preset** defines default vulnerability analysis values that the engine |
| 182 | +applies automatically to each (product_package, vulnerability) pair matched by the |
| 183 | +ruleset. |
| 184 | + |
| 185 | +.. list-table:: |
| 186 | + :header-rows: 1 |
| 187 | + |
| 188 | + * - Field |
| 189 | + - Description |
| 190 | + * - **State** |
| 191 | + - Default analysis state (e.g., ``in_triage``). |
| 192 | + * - **Justification** |
| 193 | + - Default justification value. |
| 194 | + * - **Responses** |
| 195 | + - Default response values (multiple choice). |
| 196 | + * - **Detail** |
| 197 | + - Default free-text detail. |
| 198 | + * - **Is Reachable** |
| 199 | + - Default reachability flag (true/false/unknown). |
| 200 | + |
| 201 | +Only non-blank preset fields are applied to each analysis. User-owned analyses (those |
| 202 | +not created by a preset) are never overwritten. When a user edits an auto-applied |
| 203 | +analysis, it becomes user-owned and the engine will not modify it again. |
| 204 | + |
| 205 | +Analysis Presets are managed in the Admin interface under |
| 206 | +:guilabel:`Vulnerabilities > Analysis Presets`. |
| 207 | + |
| 208 | +4.3 Request Template |
| 209 | +^^^^^^^^^^^^^^^^^^^^ |
| 210 | + |
| 211 | +When a **Request Template** is assigned to a ruleset, the engine automatically opens |
| 212 | +one DejaCode request per new triage record using the template's title and content as |
| 213 | +defaults. |
| 214 | + |
| 215 | +Key behaviors: |
| 216 | + |
| 217 | +- The template must be of content type **Product**. |
| 218 | +- The engine uses the request template's creator as the requester. A request template |
| 219 | + with no creator cannot be selected on a ruleset: this is validated when the ruleset |
| 220 | + is saved, both in the Admin and through the REST API. |
| 221 | +- The request is linked to the triage record. Users can navigate to it directly from |
| 222 | + the Recommendation column in the Vulnerabilities tab. |
| 223 | +- Requests are created once per triage record. Re-evaluation does not open additional |
| 224 | + requests for an existing record. |
| 225 | + |
| 226 | +4.4 Seeding Reference Rulesets |
| 227 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 228 | + |
| 229 | +A set of reference rulesets and analysis presets, covering common scenarios (critical |
| 230 | +exploited vulnerabilities, reachable vulnerabilities, stale vulnerabilities, dev-only |
| 231 | +packages, and more) can be seeded into a dataspace with the ``create_triage_rulesets`` |
| 232 | +management command:: |
| 233 | + |
| 234 | + ./manage.py create_triage_rulesets <dataspace_name> |
| 235 | + |
| 236 | +The command refuses to run if the dataspace already has triage rulesets. Pass |
| 237 | +``--reset`` to delete all existing rulesets and presets in the dataspace first and |
| 238 | +recreate them from scratch; you will be prompted for confirmation unless ``--noinput`` |
| 239 | +is also passed. Resetting removes every product's ruleset assignments, which must be |
| 240 | +redone manually afterward. |
| 241 | + |
| 242 | +5. Evaluation |
| 243 | +------------- |
| 244 | + |
| 245 | +5.1 Automatic Evaluation |
| 246 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 247 | + |
| 248 | +The engine re-evaluates a product's assigned rulesets automatically and immediately |
| 249 | +whenever any of the following changes occur, so results are reflected on the very next |
| 250 | +page reload without any manual action: |
| 251 | + |
| 252 | +- A **ruleset** already assigned to one or more products is edited and saved, from the |
| 253 | + Admin interface or through the REST API: every assigned product is re-evaluated. |
| 254 | +- A **ruleset is assigned to or unassigned from** a product, from the product |
| 255 | + Vulnerabilities tab or through the REST API. |
| 256 | +- A **package is added to or removed from** a product. |
| 257 | +- A **VulnerabilityAnalysis** record for a package in the product is saved or deleted. |
| 258 | + |
| 259 | +.. note:: |
| 260 | + Bulk operations (importing a CSV of packages, importing a ScanCode.io scan, or |
| 261 | + cloning a product) evaluate each affected product once in the background after the |
| 262 | + import completes, instead of once per imported row. Results may take a short moment |
| 263 | + to appear after a large bulk import. |
| 264 | + |
| 265 | +5.2 Manual Re-evaluation |
| 266 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 267 | + |
| 268 | +A full re-evaluation of every enabled ruleset against every product in a dataspace can |
| 269 | +be triggered from the command line:: |
| 270 | + |
| 271 | + ./manage.py evaluate_triage <dataspace_name> |
| 272 | + |
| 273 | +This is intended for scheduled runs or recovery after data changes. |
| 274 | + |
| 275 | +6. Vulnerabilities Tab |
| 276 | +---------------------- |
| 277 | + |
| 278 | +The **Vulnerabilities** tab on each product detail page provides a per-vulnerability |
| 279 | +view of the product's affected packages. When at least one enabled ruleset is assigned |
| 280 | +to the product, a **Recommendation** column appears. A link to open the |
| 281 | +:guilabel:`Manage Triage Rulesets` panel is available from the tab's navigation bar for |
| 282 | +users with change permission on the product. |
| 283 | + |
| 284 | +For each vulnerability row, the Recommendation cell shows: |
| 285 | + |
| 286 | +- The recommended **action** (colored badge). |
| 287 | +- The **ruleset name** that produced the recommendation. |
| 288 | +- The **detection date** (Since). |
| 289 | +- A link to the **associated request**, if one was opened automatically. |
| 290 | + |
| 291 | +When multiple rulesets are assigned and their rules overlap on the same vulnerability, |
| 292 | +only the record from the highest-precedence ruleset is displayed. |
| 293 | + |
| 294 | +Hovering the info icon next to a vulnerability ID shows a popover with its aliases, |
| 295 | +summary, exploitability, and risk score. |
| 296 | + |
| 297 | +Vulnerability analysis values (state, justification, responses, reachability) are |
| 298 | +shown in adjacent columns and can be edited inline via the edit icon. When an analysis |
| 299 | +was auto-applied by a preset, an "Auto-applied" indicator with the preset name is shown |
| 300 | +in place of the usual last-modified-by information. |
| 301 | + |
| 302 | +The table can be filtered by **Triage action**, **Analysis state**, **Justification**, |
| 303 | +**Responses**, and **Reachability**. |
| 304 | + |
| 305 | +7. REST API |
| 306 | +----------- |
| 307 | + |
| 308 | +A product's active triage recommendations are accessible via the REST API at:: |
| 309 | + |
| 310 | + GET /api/v2/products/{uuid}/triage_records/ |
| 311 | + |
| 312 | +The response is a list of active recommendations, one entry per vulnerability, from |
| 313 | +the highest-precedence matching ruleset, each including: |
| 314 | + |
| 315 | +- ``advisory_id``: the vulnerability identifier. |
| 316 | +- ``ruleset``: the name of the ruleset that produced the recommendation. |
| 317 | +- ``recommended_action``: the remediation action. |
| 318 | +- ``matched_rules``: the rule types that matched. |
| 319 | +- ``request``: a string representation of the associated request, or ``null``. |
| 320 | +- ``detected_date`` and ``last_checked``. |
| 321 | + |
| 322 | +Triage rulesets and analysis presets support full create, retrieve, update, and delete |
| 323 | +operations at:: |
| 324 | + |
| 325 | + /api/v2/triage_rulesets/ |
| 326 | + /api/v2/analysis_presets/ |
| 327 | + |
| 328 | +A product's ruleset assignments can be listed and managed at:: |
| 329 | + |
| 330 | + GET /api/v2/products/{uuid}/manage_triage_rulesets/ |
| 331 | + POST /api/v2/products/{uuid}/manage_triage_rulesets/ |
| 332 | + |
| 333 | +The ``GET`` response lists every enabled ruleset in the product's dataspace, each |
| 334 | +flagged with an ``assigned`` boolean. The ``POST`` endpoint assigns or unassigns one |
| 335 | +ruleset at a time and re-evaluates the product immediately:: |
| 336 | + |
| 337 | + {"ruleset": "<uuid>", "assigned": true} |
| 338 | + |
| 339 | +Vulnerability analyses, including whether they were auto-applied by a preset, are also |
| 340 | +available at ``/api/v2/vulnerability_analyses/``. |
0 commit comments