VYPR
High severityNVD Advisory· Published Jun 6, 2022· Updated Apr 22, 2025

DoS Vulnerability in URLEncodedFormDecoder in Vapor

CVE-2022-31019

Description

Vapor 4.61.0 and earlier have an unbounded stack growth vulnerability in URL-encoded form decoding, allowing remote DoS via crafted request.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Vapor 4.61.0 and earlier have an unbounded stack growth vulnerability in URL-encoded form decoding, allowing remote DoS via crafted request.

CVE-2022-31019 is a denial-of-service (DoS) vulnerability in the Vapor server-side Swift HTTP web framework, affecting versions prior to 4.61.1. The bug resides in the automatic content decoding feature, specifically within the URLEncodedFormData struct's recursive set(value:forPath:) method. When parsing deeply nested query parameters from an application/x-www-form-urlencoded request body, no recursion limit was enforced, leading to unbounded, attacker-controlled stack growth [1][2].

An attacker can exploit this by sending a specially crafted HTTP POST request, such as: curl -d "array[_0][0][array][_0][0][array]$(for f in $(seq 1100); do echo -n '[_0][0][array]'; done)[string][_0]=hello%20world" http://localhost:8080/foo. This causes the server to recursively process the deeply nested keys, consuming stack space until a stack overflow occurs, crashing the process [1][3]. No authentication is required, and the attack is remotely exploitable over the network.

The impact is a complete denial of service: the Vapor server process terminates unexpectedly, affecting all hosted services. There is no data exposure, but availability is severely compromised. The vulnerability has a CVSS v3.1 base score of 7.5 (High) [1].

Vapor 4.61.1, released on the same day as the advisory, fixes the issue by introducing a configurable maxRecursionDepth constant (set to 100) in the URLEncodedFormData struct, and modifying the recursive set method to throw a reachedNestingLimit error when the depth is exceeded [2][3]. As a workaround, administrators can disable URL-encoded form decoding entirely by configuring ContentConfiguration to use only JSON or other serializers [3].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/vapor/vaporSwiftURL
< 4.61.14.61.1

Affected products

2

Patches

1
6c63226a4ab8

Merge pull request from GHSA-qvxg-wjxc-r4gg

https://github.com/vapor/vaporTim CondonJun 6, 2022via ghsa
4 files changed · +20 4
  • Sources/Vapor/URLEncodedForm/URLEncodedFormData.swift+6 2 modified
    @@ -54,6 +54,7 @@ enum URLQueryFragment: ExpressibleByStringLiteral, Equatable {
     internal struct URLEncodedFormData: ExpressibleByArrayLiteral, ExpressibleByStringLiteral, ExpressibleByDictionaryLiteral, Equatable {
         var values: [URLQueryFragment]
         var children: [String: URLEncodedFormData]
    +    let maxRecursionDepth = 100
         
         var hasOnlyValues: Bool {
             return children.count == 0
    @@ -90,7 +91,10 @@ internal struct URLEncodedFormData: ExpressibleByArrayLiteral, ExpressibleByStri
             self.children = Dictionary(uniqueKeysWithValues: dictionaryLiteral)
         }
             
    -    mutating func set(value: URLQueryFragment, forPath path: [String]) {
    +    mutating func set(value: URLQueryFragment, forPath path: [String], recursionDepth: Int) throws {
    +        guard recursionDepth <= maxRecursionDepth else {
    +            throw URLEncodedFormError.reachedNestingLimit
    +        }
             guard let firstElement = path.first else {
                 self.values.append(value)
                 return
    @@ -101,7 +105,7 @@ internal struct URLEncodedFormData: ExpressibleByArrayLiteral, ExpressibleByStri
             } else {
                 child = []
             }
    -        child.set(value: value, forPath: Array(path[1...]))
    +        try child.set(value: value, forPath: Array(path[1...]), recursionDepth: recursionDepth + 1)
             self.children[firstElement] = child
         }
     }
    
  • Sources/Vapor/URLEncodedForm/URLEncodedFormError.swift+3 0 modified
    @@ -1,6 +1,7 @@
     /// Errors thrown while encoding/decoding `application/x-www-form-urlencoded` data.
     enum URLEncodedFormError: Error {
         case malformedKey(key: Substring)
    +    case reachedNestingLimit
     }
     
     extension URLEncodedFormError: AbortError {
    @@ -12,6 +13,8 @@ extension URLEncodedFormError: AbortError {
             switch self {
             case .malformedKey(let path):
                 return "Malformed form-urlencoded key encountered: \(path)"
    +        case .reachedNestingLimit:
    +            return "The data supplied is too nested"
             }
         }
     }
    
  • Sources/Vapor/URLEncodedForm/URLEncodedFormParser.swift+2 2 modified
    @@ -14,11 +14,11 @@ internal struct URLEncodedFormParser {
                 switch kv.count {
                 case 1:
                     let value = String(kv[0])
    -                result.set(value: .urlEncoded(value), forPath: [])
    +                try result.set(value: .urlEncoded(value), forPath: [], recursionDepth: 0)
                 case 2:
                     let key = kv[0]
                     let value = String(kv[1])
    -                result.set(value: .urlEncoded(value), forPath: try parseKey(key: Substring(key)))
    +                try result.set(value: .urlEncoded(value), forPath: try parseKey(key: Substring(key)), recursionDepth: 0)
                 default:
                     //Empty `&&`
                     continue
    
  • Tests/VaporTests/URLEncodedFormTests.swift+9 0 modified
    @@ -574,6 +574,15 @@ final class URLEncodedFormTests: XCTestCase {
             ])
             XCTAssertEqual(data, "test=%26%3B!$'(),/:%3D%3F@~")
         }
    +    
    +    func testHeavilyNestedArray() throws {
    +        var body = "x"
    +        body += String(repeating: "[]", count: 80000)
    +        body += "=y"
    +        struct Foo: Content {}
    +        XCTAssertThrowsError(try URLEncodedFormDecoder().decode(Foo.self, from: body))
    +        XCTAssert(true, "We should not have crashed")
    +    }
     }
     
     private struct User: Codable, Equatable {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.