Skip to content

Commit 15ae50a

Browse files
committed
Add CRLF injection protection for header values
Implement security validation to prevent HTTP header injection attacks: - Reject header values containing \r or \n characters - Add comprehensive test coverage for CRLF protection - Replace multiline YAML test with proper rejection test Security improvements: - Validates header values to prevent header injection - Clear warning messages when values are rejected - Four new test cases covering LF, CR, CRLF, and multiline scenarios This addresses a critical security concern where malicious headers could be injected via newline characters in header values. All 84 tests passing.
1 parent f773800 commit 15ae50a

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

__tests__/helpers.test.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,52 @@ valid123: value5`
283283
})
284284
})
285285

286-
it('handles multiline YAML values', () => {
286+
it('rejects header values with newline characters (LF)', () => {
287+
const jsonInput = '{"X-Custom-Header": "value\\nwith\\nnewline", "header1": "safe-value"}'
288+
289+
const result = parseCustomHeaders(jsonInput)
290+
291+
// Only the safe header should be accepted
292+
expect(result).toEqual({
293+
header1: 'safe-value',
294+
})
295+
296+
expect(core.warning).toHaveBeenCalledWith(
297+
'Skipping header "X-Custom-Header" because its value contains newline characters, which are not allowed in HTTP header values.',
298+
)
299+
})
300+
301+
it('rejects header values with carriage return characters (CR)', () => {
302+
const jsonInput = '{"X-Injected": "value\\rwith\\rcarriage", "X-Safe": "safe-value"}'
303+
304+
const result = parseCustomHeaders(jsonInput)
305+
306+
// Only the safe header should be accepted
307+
expect(result).toEqual({
308+
'X-Safe': 'safe-value',
309+
})
310+
311+
expect(core.warning).toHaveBeenCalledWith(
312+
'Skipping header "X-Injected" because its value contains newline characters, which are not allowed in HTTP header values.',
313+
)
314+
})
315+
316+
it('rejects header values with CRLF sequences', () => {
317+
const jsonInput = '{"X-Attack": "value\\r\\nInjected-Header: malicious", "X-Valid": "normal"}'
318+
319+
const result = parseCustomHeaders(jsonInput)
320+
321+
// Only the valid header should be accepted
322+
expect(result).toEqual({
323+
'X-Valid': 'normal',
324+
})
325+
326+
expect(core.warning).toHaveBeenCalledWith(
327+
'Skipping header "X-Attack" because its value contains newline characters, which are not allowed in HTTP header values.',
328+
)
329+
})
330+
331+
it('rejects multiline YAML values for security', () => {
287332
const yamlInput = `header1: value1
288333
header2: |
289334
multiline
@@ -292,8 +337,14 @@ header2: |
292337

293338
const result = parseCustomHeaders(yamlInput)
294339

295-
expect(result.header1).toBe('value1')
296-
expect(result.header2).toContain('multiline')
340+
// header2 should be rejected because it contains newlines
341+
expect(result).toEqual({
342+
header1: 'value1',
343+
})
344+
345+
expect(core.warning).toHaveBeenCalledWith(
346+
'Skipping header "header2" because its value contains newline characters, which are not allowed in HTTP header values.',
347+
)
297348
})
298349

299350
it('handles complex real-world Azure APIM example', () => {

dist/index.js

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/helpers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ function validateAndMaskHeaders(headers: Record<string, unknown>): Record<string
132132

133133
// Validate header value to prevent CRLF/header injection
134134
if (stringValue.includes('\r') || stringValue.includes('\n')) {
135-
core.warning(`Skipping header "${name}" because its value contains newline characters, which are not allowed in HTTP header values.`)
135+
core.warning(
136+
`Skipping header "${name}" because its value contains newline characters, which are not allowed in HTTP header values.`,
137+
)
136138
continue
137139
}
138140
validHeaders[name] = stringValue

0 commit comments

Comments
 (0)