{"record":{"id":"6a5668e1fecd826d","repo":"projectdiscovery/nuclei","slug":"batteringram-must-have-single-payload-set","errorCode":null,"errorMessage":"batteringram must have single payload set","messagePattern":"batteringram must have single payload set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/protocols/common/generators/generators.go","lineNumber":65,"sourceCode":"\n\tcompiled, err := generator.loadPayloads(payloadsFinal, templatePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgenerator.Type = attackType\n\tgenerator.payloads = compiled\n\n\tif customAttackType != \"\" {\n\t\tattackTypeNew, err := toAttackType(customAttackType)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"could not parse custom attack-type\")\n\t\t}\n\t\tgenerator.Type = attackTypeNew\n\t}\n\t// Validate the batteringram payload set\n\tif attackType == BatteringRamAttack {\n\t\tif len(payloads) != 1 {\n\t\t\treturn nil, errors.New(\"batteringram must have single payload set\")\n\t\t}\n\t}\n\treturn generator, nil\n}\n\ntype aggressionLevelToPayloads struct {\n\tLow    []interface{}\n\tMedium []interface{}\n\tHigh   []interface{}\n}\n\n// parsePayloadsWithAggression parses the payloads with the aggression level\n//\n// Three aggression are supported -\n//   - low\n//   - medium\n//   - high\n//","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/protocols/common/generators/generators.go#L47-L83","documentation":"Raised while compiling a payload generator in pkg/protocols/common/generators (generators.go:65). Batteringram semantics replay ONE payload list against every marker position simultaneously, so if the template declares attack: batteringram and len(payloads) != 1 the generator refuses to build. Multiple payload lists require pitchfork (parallel iteration) or clusterbomb (cartesian product).","triggerScenarios":"A fuzz template with attack: batteringram and two payload groups (e.g. usernames and passwords); also triggered when a generator is constructed programmatically with BatteringRamAttack and a multi-entry payloads map.","commonSituations":"Author starts with a batteringram template and later adds a second payload set without switching the attack mode; misunderstanding that batteringram substitutes the same value in all {{payload}} positions.","solutions":["Switch to clusterbomb when every combination of the payload sets must be tried","Switch to pitchfork when the sets are parallel (row i with row i)","Or merge down to exactly one payload set if batteringram is intended"],"exampleFix":"# before\nattack: batteringram\npayloads:\n  paths: ['/admin','/backup']\n  exts: ['.zip','.bak']\n# after\nattack: clusterbomb\npayloads:\n  paths: ['/admin','/backup']\n  exts: ['.zip','.bak']","handlingStrategy":"validation","validationCode":"if tmplAttack == generators.BatteringRamAttack && len(payloads) != 1 {\n    return errors.New(\"use clusterbomb/pitchfork for multiple payload sets\")\n}","typeGuard":null,"tryCatchPattern":"g, err := generators.NewGenerator(payloads, ..., attackType, ...)\nif err != nil && strings.Contains(err.Error(), \"batteringram must have single payload set\") { attackType = generators.ClusterBombAttack; g, err = generators.NewGenerator(...) }","preventionTips":["Default generated fuzz templates to clusterbomb when >1 payload set","Remember batteringram = one list for all positions"],"tags":["fuzzing","payloads","generators","validation"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}