cwe-explorer 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Emi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ # El sdist incluye los tests; su catálogo de ejemplo también hace falta para ejecutarlos.
2
+ recursive-include tests *.xml
3
+ # El test que comprueba que docs/pypi.md está al día necesita el README y el generador.
4
+ include README.md tools/pypi_readme.py
@@ -0,0 +1,356 @@
1
+ Metadata-Version: 2.4
2
+ Name: cwe-explorer
3
+ Version: 0.1.1
4
+ Summary: Explore the MITRE CWE hierarchy (View 1000): terminal tree, interactive explorer, web graph, ancestor/descendant queries and full CWE entries
5
+ Author-email: Emi <edm@unex.es>
6
+ License-Expression: MIT
7
+ Keywords: cwe,mitre,weakness,vulnerability,security,hierarchy,cli,tui,graph
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Environment :: Console :: Curses
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Natural Language :: English
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Security
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Dynamic: license-file
30
+
31
+ <!-- Generated from README.md by tools/pypi_readme.py: do not edit by hand. -->
32
+
33
+ # CWE Explorer
34
+
35
+ Explore the weakness hierarchy of **MITRE's View 1000** (*Complete Weakness
36
+ Hierarchy*, formerly *Research Concepts*) starting from a CWE identifier. It shows
37
+ the lineage up to the pillar the weakness descends from and the descendants below
38
+ it, lists its ancestors or descendants, direct or level by level, also as JSON, and
39
+ can show every section MITRE publishes for each weakness.
40
+
41
+ Selecting any node shows its **ID**, **description**, **type** (Pillar, Class, Base,
42
+ Variant or Compound), structure and status, and its full **lineage**: the primary
43
+ path up to the pillar plus every alternative path when the weakness has several
44
+ parents.
45
+
46
+ It works in two places:
47
+
48
+ - **Terminal**: a color tree, an interactive explorer (`--tui`) driven by mouse or
49
+ keyboard, and ancestor and descendant listings (`--ancestors`, `--descendants`).
50
+ - **Browser**: a self-contained HTML/CSS page (`--web`) with the interactive graph.
51
+
52
+ With `--detailed`, the tree, the interactive explorer and the web page also show the
53
+ full catalog entry of each CWE: consequences, mitigations, code examples, observed
54
+ CVEs, platforms, detection methods, mapping notes, references and more.
55
+
56
+ ## Installation
57
+
58
+ Requires Python 3.9 or later and has no external dependencies.
59
+
60
+ ```sh
61
+ pip install cwe-explorer # or: pipx install cwe-explorer / uv tool install cwe-explorer
62
+ cwex 79
63
+ ```
64
+
65
+ Two equivalent commands are installed: the short `cwex` and `cwe-explorer`. On
66
+ Windows, the interactive explorer (`--tui`) also needs `pip install windows-curses`;
67
+ everything else works as is.
68
+
69
+ It can also run as a module, whether installed or from a copy of the source code:
70
+
71
+ ```sh
72
+ python3 -m cwe_explorer 79
73
+ ```
74
+
75
+ The first run downloads the official catalog (`cwec_latest.xml.zip`, about 2 MB)
76
+ from cwe.mitre.org and caches it.
77
+
78
+ ## Usage
79
+
80
+ ```sh
81
+ cwex 79 # tree in the terminal (lineage + 2 levels of descendants)
82
+ cwex CWE-79 --tui # interactive explorer in the terminal
83
+ cwex 79 --web # interactive graph in the browser
84
+ cwex 664 --depth all # every descendant (also --depth 0, 1, 2...)
85
+ cwex --search "race" # search weaknesses by name
86
+ cwex 79 --ancestors # mode 1: direct ancestors (parents)
87
+ cwex 79 --descendants # mode 2: direct descendants (children)
88
+ cwex 79 --tui --detailed # every section of each CWE (also with the tree and --web)
89
+ cwex 79 --web -o xss.html --no-open # save the HTML without opening it
90
+ cwex --update # download the latest catalog again
91
+ ```
92
+
93
+ The identifier is accepted as `79`, `CWE-79` or `cwe79`. If the ID belongs to a
94
+ grouping (formerly *Categories*), a view or a deprecated entry, the tool explains
95
+ why it is not part of View 1000.
96
+
97
+ ### Terminal
98
+
99
+ ```
100
+ Ba CWE-79 Improper Neutralization of Input During Web Page Generation
101
+ Type Base: still mostly abstract, but with enough detail to infer specific
102
+ methods for detection and prevention.
103
+ Structure Simple
104
+ Status Stable
105
+ Description The product does not neutralize or incorrectly neutralizes user-
106
+ controllable input before it is placed in output that is used as a web page
107
+ that is served to other users.
108
+ Lineage CWE-707 › CWE-74 › CWE-79
109
+ ...
110
+
111
+ Hierarchy in View 1000 (CWE 5.0, depth 2)
112
+ Pi CWE-707 Improper Neutralization
113
+ └─ Cl CWE-74 Improper Neutralization of Special Elements in Output Used by a Downstr…
114
+ └─ Ba CWE-79 Improper Neutralization of Input During Web Page Generation ◀
115
+ ├─ Va CWE-80 Improper Neutralization of Script-Related HTML Tags in a Web Page
116
+ ├─ Va CWE-81 Improper Neutralization of Script in an Error Message Web Page
117
+ ├─ Va CWE-83 Improper Neutralization of Script in Attributes in a Web Page
118
+ │ └─ Va CWE-82 Improper Neutralization of Script in Attributes of IMG Tags in…
119
+ ...
120
+ ```
121
+
122
+ When a weakness has several lineages, all of them are drawn in the tree and the
123
+ subtree of descendants is shown only once.
124
+
125
+ Interactive explorer (`--tui`):
126
+
127
+ | Action | Mouse | Keyboard |
128
+ | --- | --- | --- |
129
+ | Show a node's details | click | `↑` `↓` / `j` `k` |
130
+ | Re-center the hierarchy on that node | double click | `Enter` / `→` |
131
+ | Go back to the previous node | | `⌫` / `b` / `←` |
132
+ | More or fewer levels of descendants | | `+` / `-` |
133
+ | Go to another CWE or search by name | | `/` |
134
+ | Scroll the details | wheel over the details | `J` / `K` |
135
+ | Open the details on cwe.mitre.org | | `o` |
136
+ | Open the node in the web graph | | `w` |
137
+ | Quit | | `q` |
138
+
139
+ ### Browser
140
+
141
+ - **Click** a node: shows its details in the side panel and highlights its lineage
142
+ up to the pillar (thick line: primary lineage).
143
+ - **Double click**, or the *Center the hierarchy on CWE-…* button: rebuilds the
144
+ graph around that node.
145
+ - **`+N` / `−`** on a node: expands or collapses its children. On ancestors it
146
+ reveals sibling weaknesses.
147
+ - Search by ID or name, a selector for levels of descendants, wheel zoom and drag
148
+ to pan.
149
+ - **Full screen** (button or `F` key): the graph fills the whole screen and the
150
+ details open as a floating panel when you click a node (from the bottom on
151
+ phones). Close it with `×` or `Esc`; `Esc` also leaves full screen.
152
+ - Solid edges for the primary parent and dashed edges for secondary parents.
153
+ - The page embeds all of View 1000, so you can navigate to any other CWE without
154
+ generating it again. The link `#cwe-89` opens that weakness directly. It follows
155
+ the system dark mode and adapts to phones.
156
+
157
+ By default the HTML is saved in `~/.cache/cwe-explorer/html/`. Use `-o` to choose
158
+ another path.
159
+
160
+ ### Full details (`--detailed`)
161
+
162
+ By default each node shows its type, structure, status, description, lineage and
163
+ relationships. With `--detailed` it also shows every section of the CWE catalog
164
+ entry, in the same order as cwe.mitre.org: alternate terms, background details,
165
+ common consequences, potential mitigations, modes of introduction, applicable
166
+ platforms, likelihood of exploit, demonstrative examples (with their code), observed
167
+ examples (CVEs), weakness ordinalities, detection methods, functional areas, affected
168
+ resources, dimensions, vulnerability mapping notes, notes, taxonomy mappings, related
169
+ CAPEC attack patterns, references and content history.
170
+
171
+ ```sh
172
+ cwex 79 --detailed # tree, with the full entry of CWE-79
173
+ cwex 79 --tui --detailed # the details pane of every node (scroll with J/K or the wheel)
174
+ cwex 79 --web --detailed # collapsible sections in the side panel
175
+ ```
176
+
177
+ ```
178
+ Common Consequences (3)
179
+ • Access Control, Confidentiality
180
+ Impact: Bypass Protection Mechanism; Read Application Data
181
+ The most common attack performed with cross-site scripting involves the disclosure
182
+ of private information stored in user cookies, such as session information.
183
+ ...
184
+ Demonstrative Examples (6)
185
+ • Example 1
186
+ The following code displays a welcome message on a web page based on the HTTP GET
187
+ username parameter (covers a Reflected XSS (Type 1) scenario).
188
+ Bad · PHP
189
+ │ $username = $_GET['username'];
190
+ │ echo '<div class="header"> Welcome, ' . $username . '</div>';
191
+ ```
192
+
193
+ Code examples keep their line breaks and indentation. In the browser, vulnerable
194
+ (`Bad`), fixed (`Good`) and attack snippets are marked with different colors, and the
195
+ side panel is wider.
196
+
197
+ The full entries are extracted once from the same catalog and cached separately
198
+ (`details.json`, about 9 MB), so the default mode stays light. For the same reason a
199
+ `--web --detailed` page weighs about 10 MB instead of 0.5 MB: it embeds every
200
+ weakness's entry so you can navigate to any CWE.
201
+
202
+ ### Ancestors and descendants (modes 1 and 2)
203
+
204
+ Given a CWE, lists its ancestors (mode 1) or its descendants (mode 2) in View 1000.
205
+ By default only the direct ones, that is, its parents or its children:
206
+
207
+ ```sh
208
+ cwex 79 --ancestors # parents of CWE-79
209
+ cwex 79 --descendants # children of CWE-79
210
+ cwex 425 --ancestors --depth all # every ancestor, up to the pillars
211
+ cwex 664 --descendants --depth 2 # children and grandchildren
212
+ cwex 664 --descendants -d all --json > cwe-664.json
213
+ ```
214
+
215
+ `--depth N` walks N levels and `--depth all` walks all of them. With more than one
216
+ level, the result is grouped by distance:
217
+
218
+ ```
219
+ Ba CWE-425 Direct Request
220
+ All ancestors in View 1000 (CWE 5.0): 11 (3 Pillar, 6 Class, 2 Base)
221
+
222
+ Level 1 (parents)
223
+ Cl CWE-862 Missing Authorization (primary parent)
224
+ Ba CWE-288 Authentication Bypass Using an Alternate Path or Channel (secondary parent)
225
+ Cl CWE-424 Improper Protection of Alternate Path (secondary parent)
226
+
227
+ Level 2
228
+ Cl CWE-285 Improper Authorization (via CWE-862 · primary lineage)
229
+ Ba CWE-306 Missing Authentication for Critical Functionality (via CWE-288)
230
+ Cl CWE-638 Not Using Complete Mediation (via CWE-424)
231
+ Pi CWE-693 Protection Mechanism Failure (via CWE-424)
232
+ ...
233
+ ```
234
+
235
+ The notes in parentheses explain the relationship:
236
+
237
+ - **Parents**: `primary parent` or `secondary parent`, according to the catalog's
238
+ `Ordinal="Primary"` attribute.
239
+ - **Children**: `secondary link` when the queried CWE is not the child's primary
240
+ parent, together with which one is.
241
+ - **Further levels**: `via CWE-…`, the nodes of the previous level through which the
242
+ node is reached. Ancestors on the path of primary parents are marked `primary
243
+ lineage`, and descendants that only reach the queried CWE through some secondary
244
+ parent are marked `outside its primary lineage`.
245
+
246
+ With `--json` the output includes the queried CWE (`cwe`, `name`, `abstraction`),
247
+ the mode (`mode`, `depth`), the catalog version (`catalog`), `count` and a
248
+ `results` list with one object per node:
249
+
250
+ | Field | Meaning |
251
+ | --- | --- |
252
+ | `id`, `name`, `abstraction`, `status`, `url` | The weakness's data |
253
+ | `distance` | 1 = parent or child, 2 = grandparent or grandchild… With several paths, the shortest one |
254
+ | `via` | IDs of the previous level through which the node is reached (at distance 1, the queried CWE itself) |
255
+ | `primary_parent` | Only at distance 1: whether the `ChildOf` link between both is the primary one. `null` otherwise |
256
+ | `primary_lineage` | For ancestors: whether it is on the CWE's primary lineage. For descendants: whether the CWE is on the node's primary lineage |
257
+
258
+ The `note` field explains an empty result or an incomplete lineage, and is `null`
259
+ otherwise. From Python, the same data comes from
260
+ `Hierarchy.relatives(cwe_id, "ancestors" | "descendants", depth=1)`; `depth=None`
261
+ walks every level:
262
+
263
+ ```python
264
+ from cwe_explorer.data import load_catalog
265
+ from cwe_explorer.hierarchy import Hierarchy
266
+
267
+ h = Hierarchy(load_catalog())
268
+ [r.id for r in h.relatives(79, "ancestors")] # [74]
269
+ [(r.id, r.distance) for r in h.relatives(83, "ancestors", depth=None)]
270
+ # [(79, 1), (74, 2), (707, 3)]
271
+ ```
272
+
273
+ ## Limitations of ancestors and descendants
274
+
275
+ Both modes can be computed from the data MITRE publishes, but View 1000 is not a
276
+ simple tree, and that shapes how the results should be read. Figures are from the
277
+ CWE 5.0 catalog (2026-10-28).
278
+
279
+ 1. **It is a graph with multiple parents, not a tree.**
280
+ - 152 of the 957 weaknesses have more than one direct parent, up to 3 (CWE-396,
281
+ CWE-397, CWE-415, CWE-425 and CWE-1299). Of the 1106 `ChildOf` links, 160 are
282
+ secondary.
283
+ - That is why mode 1 can return several parents, and the full list of ancestors
284
+ can span several branches: 279 weaknesses have more than one lineage and 235
285
+ reach more than one pillar (CWE-425 reaches three).
286
+ - MITRE only marks which parent is the primary one. The other parents have no
287
+ order of importance.
288
+ 2. **"Direct" means a `ChildOf` link, not the next abstraction level.** Links do not
289
+ always go down one step Pillar → Class → Base → Variant:
290
+ - 83 Bases and 3 Variants (CWE-580, CWE-581 and CWE-1077) hang directly from a
291
+ Pillar, and 85 Variants hang from a Class.
292
+ - 177 links join weaknesses of the same type: 88 Base–Base, 62 Class–Class and
293
+ 27 Variant–Variant.
294
+ - 2 Classes hang from a Base: CWE-114 from CWE-73 and CWE-240 from CWE-237.
295
+
296
+ The tool returns what the catalog publishes; it does not infer parents from the
297
+ type.
298
+ 3. **The same ancestor can be at several distances.**
299
+ - In 25 weaknesses there are paths of different lengths to the same ancestor.
300
+ For example, CWE-102 reaches CWE-707 in 3 levels and also in 4.
301
+ - In 4 cases, a direct parent is also a more distant ancestor (CWE-240, CWE-415,
302
+ CWE-425 and CWE-1262).
303
+
304
+ Each node appears only once, at the shortest distance, and `via` tells how it is
305
+ reached. `--depth N` also counts levels along the shortest path. The other paths
306
+ are visible with `cwex <id>`, which draws every lineage, or in the web graph.
307
+ 4. **Only View 1000 and only `ChildOf`.**
308
+ - Other views have their own hierarchy. Some use `ChildOf` with another
309
+ `View_ID` (for example 1003, the one NVD uses, or 1305). Others are organized
310
+ with groupings and `Has_Member` (for example 699). This tool loads none of
311
+ them.
312
+ - The 431 groupings (formerly *Categories*) and the 62 views are not weaknesses.
313
+ If you query one, the tool explains what it is and exits with an error instead
314
+ of listing its members.
315
+ - The XML does not publish `ParentOf` relationships: children are obtained by
316
+ inverting the `ChildOf` links.
317
+ 5. **Other relationships are not kinship.** `CanPrecede` (148), `PeerOf` (103),
318
+ `CanAlsoBe` (28), `Requires` (13), `StartsWith` (3) and `Overlaps` (3) are not
319
+ hierarchical and are not followed. They appear in each CWE's details
320
+ (`cwex <id>`).
321
+ 6. **Compounds have no children.** The 7 Compound weaknesses (for example CWE-352)
322
+ are leaves of View 1000, because their components are linked with `Requires` or
323
+ `StartsWith`. Mode 2 explains this and names those components, but does not
324
+ count them as descendants.
325
+ 7. **Some empty results are expected.** The 10 Pillars have no ancestors, and 692
326
+ weaknesses have no descendants: 390 Bases, 274 Variants, 21 Classes and the 7
327
+ Compounds. In those cases the tool adds a note (`note` in JSON) and exits with
328
+ code 0.
329
+ 8. **Deprecated entries.** The 27 deprecated entries outside the view cannot be
330
+ queried. The exception is CWE-377: it is deprecated, but CWE-378 and CWE-379
331
+ still hang from it. So their ancestors stop at CWE-377, with an incomplete
332
+ lineage warning.
333
+ 9. **Results depend on the catalog version.** MITRE changes relationships between
334
+ versions. The tool uses the cached copy until you run `cwex --update`.
335
+
336
+ ## Data
337
+
338
+ - Source: <https://cwe.mitre.org/data/xml/cwec_latest.xml.zip>. Only `ChildOf`
339
+ relationships with `View_ID="1000"` are used, and the parent marked
340
+ `Ordinal="Primary"` defines the primary lineage.
341
+ - Cache: `~/.cache/cwe-explorer/`, or `$XDG_CACHE_HOME/cwe-explorer`, or the path in
342
+ `CWEX_CACHE`. It holds the downloaded catalog, a compact `catalog.json` for the
343
+ hierarchy and, once `--detailed` has been used, `details.json` with the full
344
+ entries. Both JSON files are rebuilt when the catalog changes.
345
+ - To work offline with a specific XML: `cwex 79 --xml cwec_v5.0.xml` (the `.zip` is
346
+ accepted too).
347
+ - The parser does not depend on the schema namespace (`cwe-7`, `cwe-8`...), so it
348
+ works with old and new catalogs.
349
+
350
+ > In CWE 5.0, CWE-378 and CWE-379 still hang from CWE-377, which is marked as
351
+ > deprecated. The tool keeps that link as MITRE publishes it, marks the node as
352
+ > deprecated and warns that the lineage does not reach a pillar.
353
+
354
+ ## License
355
+
356
+ MIT © 2026 Emi