Vultron Case States Module
vultron.core.case_states
The vultron.core.case_states package implements the CVD Case State Model.
vultron.core.case_states.hypercube
The vultron.core.case_states.hypercube module contains the CVDmodel class, which represents the state graph of a Coordinated Vulnerability Disclosure case.
Based on Householder, A. D., and Jonathan Spring. A State-Based Model for Multi-Party Coordinated Vulnerability Disclosure (MPCVD). Tech. Rep. CMU/SEI-2021-SR-021, Software Engineering Institute, Carnegie-Mellon University, Pittsburgh, PA, 2021.
DESIDERATA = (('V', 'P'), ('V', 'X'), ('V', 'A'), ('F', 'P'), ('F', 'X'), ('F', 'A'), ('D', 'P'), ('D', 'X'), ('D', 'A'), ('P', 'X'), ('P', 'A'), ('X', 'A'))
module-attribute
Taken directly from the paper: Given (A,B), you prefer histories in which A precedes B over ones in which B precedes A.
CVDmodel
A CVDmodel is a graph of states and transitions between them. The model reflects the CVD process and the actions that can be taken at a high level. It also has a set of histories that can be scored.
histories
property
A list of all possible case histories traversing the case state space from vfdpxa to VFDPXA.
states
property
Returns the states in the model
compute_pagerank()
Compute the pagerank of each state in the model. Runs the NetworkX pagerank algorithm on the model graph 10000 times. Because the model is a directed graph, we need to add a wraparound link so that the pagerank algorithm can walk from the end back to the beginning naturally.
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
a dict of state: pagerank |
find_states(pat)
Find states that match a given pattern Args: pat: a regex pattern to match
Returns:
| Type | Description |
|---|---|
list
|
a list of states that match the pattern |
Raises:
| Type | Description |
|---|---|
CVDmodelError
|
if the pattern is invalid |
move_score(from_state, to_state)
Compute the score of moving from one state to another Args: from_state: The state to move from to_state: The state to move to
Returns:
| Type | Description |
|---|---|
float
|
the score of the move |
paths_between(start='vfdpxa', end='VFDPXA')
Return all paths of transitions between two states
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
the start state, default="vfdpxa" |
'vfdpxa'
|
end
|
str
|
the end state, default="VFDPXA" |
'VFDPXA'
|
Returns:
| Type | Description |
|---|---|
list[Any] | None
|
a list of paths |
paths_from(state='vfdpxa')
Return all paths of transitions that lead from a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return paths from, default="vfdpxa" |
'vfdpxa'
|
Returns:
| Type | Description |
|---|---|
list[Any] | None
|
a list of paths |
paths_to(state='VFDPXA')
Return all paths of transitions that lead to a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return paths to, default="VFDPXA" |
'VFDPXA'
|
Returns:
| Type | Description |
|---|---|
list[Any] | None
|
a list of paths |
previous_state(state)
For a given state, return the previous state(s)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return the previous state(s) for |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
a list of previous states |
score_hist(h)
Compute the score for a given history
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h
|
str
|
the history to score |
required |
Returns:
| Type | Description |
|---|---|
float
|
the score for the history |
sequences_between(start='vfdpxa', end='VFDPXA')
Return all sequences of transitions between two states
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
the start state, default="vfdpxa" |
'vfdpxa'
|
end
|
str
|
the end state, default="VFDPXA" |
'VFDPXA'
|
Returns:
| Type | Description |
|---|---|
list[tuple[str]]
|
a list of sequences |
sequences_from(state='vfdpxa')
Return all sequences of transitions that lead from a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return sequences from |
'vfdpxa'
|
Returns:
| Type | Description |
|---|---|
list[tuple[str]]
|
a list of sequences |
sequences_to(state)
Return all sequences of transitions that lead to a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return sequences to |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[str]]
|
a list of sequences |
state_adjacency_matrix()
Return the state adjacency matrix for the model
Returns:
| Type | Description |
|---|---|
DataFrame
|
a dataframe of the state adjacency matrix |
state_info(state)
Returns the info for a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state to return info for |
required |
Returns:
| Type | Description |
|---|---|
dict
|
a dict of info for the state |
state_transition_matrix()
Return the state transition matrix for the model Returns: a dataframe of the state transition matrix
transitions_in_path(path)
Return the transitions in a path
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
list
|
a list of graph edges |
required |
Returns:
| Type | Description |
|---|---|
tuple[str]
|
a tuple of the edge labels |
walk_from(start=None, end='VFDPXA')
Randomly walk from a given state to a given state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str | None
|
the start state, default=None |
None
|
end
|
str
|
the end state, default="VFDPXA" |
'VFDPXA'
|
Returns:
| Type | Description |
|---|---|
tuple
|
a tuple of the path and the probabilities of each step |
vultron.core.states.cs
The vultron.core.states.cs module implements the CVD Case State Model enums.
It also provides functions for converting between state strings and enums.
AttackObservation
Bases: StrEnum
Represents the attack observation state of a case.
CS_d
Bases: StrEnum
Deployer-path sub-machine: fix deployment (2 states).
Monotone ladder: d → D.
CS_pxa
Bases: Enum
Represents the public state of a case.
pxaindicates the public is unaware, no exploit has been published, and no attacks have been observed.Pxaindicates the public is aware, no exploit has been published, and no attacks have been observed.pxAindicates the public is unaware, no exploit has been published, and attacks have been observed.PxAindicates the public is aware, no exploit has been published, and attacks have been observed.pXaindicates the public is unaware, an exploit has been published, and no attacks have been observed.pXAindicates the public is unaware, an exploit has been published, and attacks have been observed.PXaindicates the public is aware, an exploit has been published, and no attacks have been observed.PXAindicates the public is aware, an exploit has been published, and attacks have been observed.
Note that pXa and pXA are ephemeral states: the pX→PX invariant means that once an exploit is published the public immediately becomes aware, so these states resolve to PXa/PXA in practice.
CS_vf
Bases: StrEnum
Vendor-path sub-machine: vendor awareness + fix readiness (3 states).
Monotone ladder: vf → Vf → VF.
DState
Bases: NamedTuple
Deployer-path sub-machine state (D bit only).
ExploitPublication
Bases: StrEnum
Represents the exploit publication state of a case.
FixDeployment
Bases: StrEnum
Represents the fix deployment state of a case.
FixReadiness
Bases: StrEnum
Represents the fix readiness state of a case.
PublicAwareness
Bases: StrEnum
Represents the public awareness state of a case.
PxaState
Bases: NamedTuple
Represents the public exploit path state of a case.
State
Bases: NamedTuple
Represents the state of a case.
VendorAwareness
Bases: StrEnum
Represents the vendor awareness state of a case.
VfState
Bases: NamedTuple
Vendor-path sub-machine state (V+F bits only).
create_pxa_machine()
Generates a new Case State Public Exploit Attacks Machine object
Returns:
| Name | Type | Description |
|---|---|---|
Machine |
Machine
|
New Machine object |
is_d_fix_deployed(state)
Return True when fix deployment is set (D bit).
Examples::
is_d_fix_deployed(CS_d.D) # True
is_d_fix_deployed(CS_d.d) # False
is_monotonic_d_forward(source, dest)
Return True if (source → dest) advances D without regressing.
Examples::
is_monotonic_d_forward(CS_d.d, CS_d.D) # True
is_monotonic_d_forward(CS_d.D, CS_d.d) # False (D un-set)
is_monotonic_d_forward(CS_d.d, CS_d.d) # False (no change)
is_monotonic_pxa_forward(source, dest)
Return True if (source → dest) advances PXA without regressing.
The P/X/A components are mutually independent one-way latches, so any
combination of them being newly set is monotone forward — including
multi-component jumps such as pxa → PXA that
:func:is_valid_pxa_transition does not recognise.
Equality returns False (nothing advanced). Mirrors
:func:vultron.core.states.rm.is_monotonic_rm_forward.
Examples::
is_monotonic_pxa_forward(CS_pxa.pxa, CS_pxa.PXa) # True
is_monotonic_pxa_forward(CS_pxa.Pxa, CS_pxa.pxa) # False (P un-set)
is_monotonic_pxa_forward(CS_pxa.PxA, CS_pxa.PXa) # False (A un-set)
is_monotonic_vf_forward(source, dest)
Return True if (source → dest) advances VF without regressing.
Examples::
is_monotonic_vf_forward(CS_vf.vf, CS_vf.VF) # True
is_monotonic_vf_forward(CS_vf.Vf, CS_vf.Vf) # False (no change)
is_monotonic_vf_forward(CS_vf.VF, CS_vf.Vf) # False (F un-set)
is_pxa_assertion_acceptable(current, asserted)
Return True if a received CaseStatus may move PXA current → asserted.
The PXA acceptance rule for a received status (RSH-09-003, RSH-09-005):
the asserted state is the current one, or a monotone forward move from
it. Deliberately weaker than :func:is_valid_pxa_transition, which
applies only to local writes (CSB-16-002). The CASE_MANAGER applies it
to a received CaseStatus and ParticipantStatus and when adopting a
report's P/X/A; a replica copies the entry instead (CM-23-016).
is_pxa_attacks_observed(state)
Return True if attacks have been observed in the wild (A bit set).
Examples::
is_pxa_attacks_observed(CS_pxa.pxA) # True
is_pxa_attacks_observed(CS_pxa.PXA) # True
is_pxa_attacks_observed(CS_pxa.pxa) # False
is_pxa_exploit_public(state)
Return True if exploit code is publicly available (X bit set).
Note: pX is transient — the pX→PX invariant means an exploit being public without public awareness is ephemeral; in practice P will also be set. This predicate reflects the X bit only.
Examples::
is_pxa_exploit_public(CS_pxa.pXa) # True
is_pxa_exploit_public(CS_pxa.PXA) # True
is_pxa_exploit_public(CS_pxa.Pxa) # False
is_pxa_public_aware(state)
Return True if the public is aware of the vulnerability (P bit set).
Examples::
is_pxa_public_aware(CS_pxa.Pxa) # True
is_pxa_public_aware(CS_pxa.PXA) # True
is_pxa_public_aware(CS_pxa.pxa) # False
is_valid_d_transition(source, dest)
Return True if (source → dest) is a valid D state transition.
is_valid_pxa_transition(source, dest)
Return True if (source → dest) is a valid PXA state transition.
is_valid_vf_transition(source, dest)
Return True if (source → dest) is a valid VF state transition.
is_vf_fix_ready(state)
Return True when fix readiness is set (F bit; implies vendor awareness).
Examples::
is_vf_fix_ready(CS_vf.VF) # True
is_vf_fix_ready(CS_vf.Vf) # False
is_vf_fix_ready(CS_vf.vf) # False
is_vf_vendor_aware(state)
Return True when vendor awareness is set (V bit in the VF path).
Examples::
is_vf_vendor_aware(CS_vf.Vf) # True
is_vf_vendor_aware(CS_vf.VF) # True
is_vf_vendor_aware(CS_vf.vf) # False
state_string_to_enum2(s)
Convert a state string to a list of enums that define the state
Example
state_string_to_enum2('vfdpxa')
( VendorAwareness.VENDOR_UNAWARE,
FixReadiness.FIX_NOT_READY,
FixDeployment.FIX_NOT_DEPLOYED,
PublicAwareness.PUBLIC_UNAWARE,
ExploitPublication.NO_PUBLIC_EXPLOIT,
AttackObservation.NO_ATTACKS_OBSERVED)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
s
|
str
|
the state string |
required |
Returns:
| Type | Description |
|---|---|
tuple[StrEnum, ...]
|
a list of Enums |
vultron.core.case_states.validations
This module contains functions to validate the various strings and patterns used by the CVD State Model
CS_EVENT_LETTERS = tuple('VFDPXA')
module-attribute
The six case-state events, in the order a state string spells them.
ensure_valid_history(func)
Decorator to ensure a valid history is passed to a function
Example
@ensure_valid_history
def my_func(history, ...):
...
Args: func: the function to decorate
Returns:
| Type | Description |
|---|---|
F
|
the decorated function |
Raises:
| Type | Description |
|---|---|
HistoryValidationError
|
if the history is invalid |
ensure_valid_pattern(func)
Function decorator to ensure a valid pattern is passed to a function
Example
@ensure_valid_pattern
def my_func(pattern, ...):
...
Args: func: the function to decorate
Returns:
| Type | Description |
|---|---|
F
|
the decorated function |
ensure_valid_state(func)
Function Decorator to ensure a valid state is passed to a function
Example
@ensure_valid_state
def my_func(state, ...):
...
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
F
|
the function to decorate |
required |
Returns:
| Type | Description |
|---|---|
F
|
the decorated function |
ensure_valid_state_method_wrapper(func)
Method Decorator to ensure a valid state is passed to a method. Equivalent to ensure_valid_state, but for methods.
Example
class MyClass:
@ensure_valid_state_method_wrapper
def my_method(self, state, ...):
...
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
F
|
the method to decorate |
required |
Returns:
| Type | Description |
|---|---|
F
|
the decorated method |
is_valid_history(h)
Validate a history string. Checks that the history is exactly six characters long, is all uppercase, and contains one each of V, F, D, P, X, and A. Also checks that the causally-related events are in the correct order:
- V \(\prec\) F \(\prec\) D
- P \(\prec\) X or XP
- V \(\prec\) P or PV
Example
is_valid_history("VFDPXA")
is_valid_history("VFDPX")
HistoryValidationError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h
|
str
|
the history string to validate |
required |
Returns:
| Type | Description |
|---|---|
None
|
None |
Raises:
| Type | Description |
|---|---|
HistoryValidationError
|
if the history is invalid |
is_valid_pattern(pat)
Validate a pattern string. Patterns are expected to be regular expressions with the following constraints:
- The pattern is exactly six characters long.
- The pattern contains either upper or lower case v, f, d, p, x, a, in that order, or a dot.
Examples:
is_valid_pattern("vfdpxa")
is_valid_pattern("Vfd.X.")
is_valid_pattern("xpdfva")
is_valid_pattern("vfDPx")
PatternValidationError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pat
|
str
|
the pattern string to validate |
required |
Returns:
| Type | Description |
|---|---|
None
|
None |
Raises:
| Type | Description |
|---|---|
PatternValidationError
|
if the pattern is invalid |
is_valid_state(state)
Validate a state string.
Checks that the state is a valid state pattern.
Also checks that the state is not impossible (e.g. vF...., .fD...)
Finally, verifies that only allowed symbols (vVfFdDpPxXaA.) are used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
the state string to validate |
required |
Returns:
| Type | Description |
|---|---|
None
|
None |
Raises:
| Type | Description |
|---|---|
StateValidationError
|
if the state is invalid |
is_valid_transition(src, dst, allow_null=False)
Validate a transition from src to dst
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
str
|
the source state |
required |
dst
|
str
|
the destination state |
required |
allow_null
|
bool
|
if True, allow null transitions (src==dst), default=False |
False
|
Returns:
| Type | Description |
|---|---|
None
|
None |
Raises:
| Type | Description |
|---|---|
TransitionValidationError
|
if the transition is invalid |
valid_states()
Return every valid case-state string, in lattice product order.
Enumerates each upper/lower-case combination of :data:CS_EVENT_LETTERS
and keeps those :func:is_valid_state accepts. The hypercube model builds
its state graph from this list, and the pattern modules' report scripts
iterate it directly, so neither needs the other to enumerate states.