T09 · Insecure Skill Coding Practices
- Location
SKILL.md:41- Finding
Unbounded HTTP Response Buffering Can Cause Memory Exhaustion
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 41–47
Vulnerability Type: Unbounded resource consumption
Risk Level: MediumVulnerable Code:
go func FetchData(ctx context.Context, url string) ([]byte, error) { req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, err } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) }Technical Analysis
The example is presented as a production-ready HTTP pattern but passes
resp.Bodydirectly toio.ReadAll. This operation continues allocating memory until the response reaches EOF or an error occurs, with no application-level maximum response size.A context deadline limits how long the request may run, but it does not establish a memory limit. A malicious or compromised server can transmit a large response rapidly enough to exhaust substantial memory before the deadline. The example also does not inspect the HTTP status or declared
Content-Lengthbefore buffering the body.Because this is documentation rather than executable project code, exploitation requires a downstream application to adopt the pattern and request an attacker-controlled, compromised, or redirectable endpoint.
Attack Path
- A downstream application implements the documented
FetchDatapattern. - The application requests a URL controlled by an attacker, or an otherwise trusted endpoint is compromised or redirects to an attacker-controlled server.
- The server responds with a very large or continuously generated body.
io.ReadAll(resp.Body)repeatedly expands its in-memory buffer without enforcing a size ceiling.- The process experiences elevated memory consumption and may be terminated by the operating system or become unavailable.
Impact Assessment
Successful exploitation can cause application-level den ...[truncated 360 chars]
- A downstream application implements the documented
- Remediation
View remediation
Remediation Suggestions
Enforce an application-specific response-size limit before fully buffering the body:
- Check
Content-Lengthwhen present and reject values above the configured maximum. - Wrap the response body with
io.LimitReader, usingmaxSize + 1so the application can detect overflow. - Return an explicit error when the response exceeds the limit.
- Validate the HTTP status code before reading the response body.
- Retain context deadlines and configure an
http.Clientwith appropriate transport and timeout settings.
Example hardened pattern:
go const maxResponseSize int64 = 10 << 20 // 10 MiB func FetchData(ctx context.Context, url string) ([]byte, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("create request: %w", err) } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("perform request: %w", err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, fmt.Errorf("unexpected HTTP status: %s", resp.Status) } if resp.ContentLength > maxResponseSize { return nil, fmt.Errorf("response exceeds %d-byte limit", maxResponseSize) } data, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1)) if err != nil { return nil, fmt.Errorf("read response: %w", err) } if int64(len(data)) > maxResponseSize { return nil, fmt.Errorf("response exceeds %d-byte limit", maxResponseSize) } return data, nil }- Check
