cwe.cr

cwe.cr

A Crystal implementation of the MITRE CWE (Common Weakness Enumeration). The full CWE Research view (view 1000) is embedded at compile time, so lookups, search, and relationship traversal need no network access or sidecar data files.

require "cwe"

w = CWE.find!("CWE-79")
w.name        # => "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')"
w.abstraction # => CWE::Abstraction::Base
w.status      # => CWE::Status::Stable
w.url         # => "https://cwe.mitre.org/data/definitions/79.html"

w.common_consequences.first.scope # => "Confidentiality"
w.potential_mitigations.size      # => 12
w.parent_relations.map(&.cwe_id)  # => [74, 74]

Installation

Add to your shard.yml:

dependencies:
  cwe:
    github: hahwul/cwe.cr

Then shards install.

Usage

Lookups

CWE.find!("CWE-79")  # raises CWE::NotFoundError if missing
CWE.find(79)         # returns nil if missing
CWE[79]              # bang variant, same as find!
CWE[79]?             # nil variant, same as find
CWE.includes?("CWE-79") # => true

Any of these forms is accepted as an id: 79, "79", "CWE-79", "cwe-79", "CWE_79", "CWE:79". Whitespace around the value is tolerated.

Entry fields

Each CWE::Weakness exposes:

field type
id, cwe_id, url Int32, "CWE-79", https://...
name String
abstraction CWE::Abstraction (Pillar, Class, Base, Variant, Compound)
structure CWE::Structure (Simple, Composite, Chain)
status CWE::Status (Stable, Draft, Incomplete, Deprecated, …)
description, extended_description String?
likelihood_of_exploit String?
related_weaknesses Array(CWE::Related)ChildOf / ParentOf / PeerOf / CanPrecede / CanFollow
common_consequences Array(CWE::Consequence) — scope + impact + note
potential_mitigations Array(CWE::Mitigation) — phase + strategy + description
detection_methods Array(CWE::DetectionMethod)
observed_examples Array(CWE::ObservedExample) — CVE references
demonstrative_examples Array(CWE::DemonstrativeExample) — code samples (Bad/Good/Attack)
applicable_platforms Array(CWE::ApplicablePlatform)
alternate_terms Array(CWE::AlternateTerm)
modes_of_introduction Array(CWE::ModeOfIntroduction)
taxonomy_mappings Array(CWE::TaxonomyMapping) — PLOVER, OWASP, CAPEC, …
related_attack_patterns Array(Int32) — CAPEC ids
references Array(CWE::ReferenceLink)REF-N citations
mapping_notes CWE::MappingNotes? — usage policy + rationale
content_history CWE::ContentHistory? — submission / last-modification dates
notes Array(CWE::Note)

Convenience helpers:

w = CWE.find!("CWE-79")
w.mapping_usage   # => CWE::MappingUsage::Allowed
w.mappable?       # => true
w.compound?       # => false  (Simple structure)
w.deprecated?     # => false

Mapping policy

CWE 4.x assigns each entry a mapping Usage so tooling knows whether the entry is an acceptable target for a CVE / finding (Allowed, Allowed-with-Review, Discouraged, Prohibited). Categories and Views are always Prohibited.

CWE.find!(79).mapping_usage         # => CWE::MappingUsage::Allowed
CWE.find!(20).mapping_usage         # => CWE::MappingUsage::Discouraged (Class-level)
CWE.category!(227).mapping_usage    # => CWE::MappingUsage::Prohibited

Demonstrative examples

w = CWE.find!(89)  # SQL Injection
ex = w.demonstrative_examples.first
ex.intro_text                     # prose intro
ex.example_code.first.language    # => "Java"
ex.example_code.first.nature      # => "Bad"
ex.example_code.first.code        # the snippet

External references

CWE stores all citations once in a catalog-level registry; individual entries link to them by id.

w = CWE.find!(79)
link = w.references.first         # => CWE::ReferenceLink(@external_reference_id="REF-709", …)
ref  = CWE.external_reference!(link.external_reference_id)
ref.title    # => "OWASP …"
ref.url      # => "https://…"

CWE.external_references.size  # => 1000+

Walking the hierarchy

CWE.parents_of(79)       # => [CWE-74]
CWE.children_of(79)      # => [CWE-80, CWE-81, CWE-83, CWE-84, CWE-85, CWE-86, CWE-87]
CWE.ancestors_of(79)     # nearest-first transitive closure
CWE.descendants_of(79)
CWE.pillar_of(79)        # => CWE-707

# All edges are O(1) lookups via a pre-built index. Pass view_id to restrict
# to a particular CWE view (1000 = Research, 1003 = Simplified Mapping):
CWE.parents_of(79, view_id: 1000)

Search

CWE.search_by_name("cross-site scripting") # name-only match
CWE.search("HttpOnly")                     # name + description + alternate terms
CWE.with_abstraction(CWE::Abstraction::Pillar)
CWE.with_status(CWE::Status::Stable)

JSON

require "json"

CWE.find!(79).to_json
# {
#   "id": 79,
#   "cweId": "CWE-79",
#   "name": "Improper Neutralization of Input During Web Page Generation (...)",
#   "abstraction": "Base",
#   "status": "Stable",
#   "commonConsequences": [...],
#   "potentialMitigations": [...],
#   ...
# }

Categories and Views

CWE includes the full MITRE catalog — not just Weaknesses, but also Categories (informal groupings, "Mapping Prohibited") and Views (slices of the catalog organised around a stakeholder's perspective).

CWE.category!(227)  # => CWE::Category: "7PK - API Abuse" (10 members)
CWE.view!(1000)     # => CWE::View: "Research Concepts" (Graph)
CWE.members_of(1000) # => Array(CWE::Weakness) — the resolved members

# Unified lookup when you don't know which kind of entity an id refers to:
CWE.entry(79)    # => Weakness
CWE.entry(227)   # => Category
CWE.entry(1000)  # => View
CWE.entry(99999) # => nil

Catalog metadata

CWE.catalog_version           # => "4.20"
CWE.size                      # => 944  (weaknesses)
CWE.categories.size           # => 422
CWE.views.size                # => 59
CWE.external_references.size  # => 1026

Examples

Runnable scripts under examples/:

crystal run examples/basic.cr

Development

Run the test suite:

crystal spec

Regenerate the embedded data blob from a fresh MITRE CWE export:

# Drop both files at data/, then:
#   data/cwec.csv         — MITRE "view 1000" CSV
#   data/cwec_v4.20.xml   — full XML (needed for Categories, Views,
#                           Demonstrative_Examples, Mapping_Notes,
#                           References, Content_History, Audience)
crystal run data/build_data.cr
crystal spec

The build is incremental — without the XML the catalog still loads, it just won't include Categories, Views, or any of the XML-only blocks.

The embedded data lives at src/cwe/data/weaknesses.json and is read into the binary at compile time via {{ read_file(...) }}.

License

MIT © hahwul

This library redistributes data from the MITRE Common Weakness Enumeration, which is released under MITRE's terms of use. CWE™ is a trademark of The MITRE Corporation.

Repository

cwe.cr

Owner
Statistic
  • 1
  • 0
  • 0
  • 0
  • 0
  • about 3 hours ago
  • May 19, 2026
License

MIT License

Links
Synced at

Tue, 19 May 2026 15:25:21 GMT

Languages