Skip to content

Commit

Permalink
Added nil checks around OWASP rules
Browse files Browse the repository at this point in the history
found a way to explode them using a malformed openapi spec.

Signed-off-by: quobix <dave@quobix.com>
  • Loading branch information
daveshanley committed Jan 24, 2024
1 parent 3330e3a commit 2fffb5c
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 273 deletions.
34 changes: 17 additions & 17 deletions functions/owasp/auth_insecure_schemes.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ func (is AuthInsecureSchemes) RunRule(_ []*yaml.Node, context model.RuleFunction
return results
}

ss := context.DrDocument.V3Document.Components.SecuritySchemes
for schemePairs := ss.First(); schemePairs != nil; schemePairs = schemePairs.Next() {

scheme := schemePairs.Value()
if scheme.Value.Type == "http" {
if strings.ToLower(scheme.Value.Scheme) == "negotiate" ||
strings.ToLower(scheme.Value.Scheme) == "oauth" {
node := scheme.Value.GoLow().Scheme.KeyNode
result := model.RuleFunctionResult{
Message: utils.SuppliedOrDefault(context.Rule.Message, "authentication scheme is considered outdated or insecure"),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("%s.%s", scheme.GenerateJSONPath(), "scheme"),
Rule: context.Rule,
if context.DrDocument.V3Document != nil && context.DrDocument.V3Document.Components != nil {
ss := context.DrDocument.V3Document.Components.SecuritySchemes
for schemePairs := ss.First(); schemePairs != nil; schemePairs = schemePairs.Next() {
scheme := schemePairs.Value()
if scheme.Value.Type == "http" {
if strings.ToLower(scheme.Value.Scheme) == "negotiate" ||
strings.ToLower(scheme.Value.Scheme) == "oauth" {
node := scheme.Value.GoLow().Scheme.KeyNode
result := model.RuleFunctionResult{
Message: utils.SuppliedOrDefault(context.Rule.Message, "authentication scheme is considered outdated or insecure"),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("%s.%s", scheme.GenerateJSONPath(), "scheme"),
Rule: context.Rule,
}
scheme.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
scheme.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)

}
}
}
Expand Down
95 changes: 48 additions & 47 deletions functions/owasp/check_error_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,61 +42,62 @@ func (er CheckErrorResponse) RunRule(_ []*yaml.Node, context model.RuleFunctionC
if doc.GetSpecInfo().VersionNumeric <= 2 {
return results
}
if drDoc.Paths != nil && drDoc.Paths.PathItems != nil {
for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
for opPairs := pathPairs.Value().GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()
opType := opPairs.Key()

for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
for opPairs := pathPairs.Value().GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()
opType := opPairs.Key()
responses := opValue.Responses.Codes
found := false
schemaMissing := true
var node *yaml.Node

responses := opValue.Responses.Codes
found := false
schemaMissing := true
var node *yaml.Node

for respPairs := responses.First(); respPairs != nil; respPairs = respPairs.Next() {
resp := respPairs.Value()
respCode := respPairs.Key()
if respCode == code {
found = true
node = resp.Value.GoLow().Content.KeyNode
if resp.Content.First() != nil {
if resp.Content.First().Value().Value.Schema != nil {
schemaMissing = false
for respPairs := responses.First(); respPairs != nil; respPairs = respPairs.Next() {
resp := respPairs.Value()
respCode := respPairs.Key()
if respCode == code {
found = true
node = resp.Value.GoLow().Content.KeyNode
if resp.Content.First() != nil {
if resp.Content.First().Value().Value.Schema != nil {
schemaMissing = false
}
}
}
}
}
if node == nil {
n := responses.GetOrZero(code)
if n != nil {
node = n.Value.GoLow().RootNode
} else {
node = opValue.Responses.Value.GoLow().KeyNode
if node == nil {
n := responses.GetOrZero(code)
if n != nil {
node = n.Value.GoLow().RootNode
} else {
node = opValue.Responses.Value.GoLow().KeyNode
}
}
}
if !found {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing response code `%s` for `%s`", code, strings.ToUpper(opType))),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("$.paths['%s'].%s.responses", pathPairs.Key(), opType),
Rule: context.Rule,
if !found {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing response code `%s` for `%s`", code, strings.ToUpper(opType))),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("$.paths['%s'].%s.responses", pathPairs.Key(), opType),
Rule: context.Rule,
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
if schemaMissing && found {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing schema for `%s` response on `%s`", code, strings.ToUpper(opType))),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("$.paths['%s'].%s.responses['%s']", pathPairs.Key(), opType, code),
Rule: context.Rule,
if schemaMissing && found {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing schema for `%s` response on `%s`", code, strings.ToUpper(opType))),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("$.paths['%s'].%s.responses['%s']", pathPairs.Key(), opType, code),
Rule: context.Rule,
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
}
}
Expand Down
157 changes: 80 additions & 77 deletions functions/owasp/check_security.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,92 +42,95 @@ func (cd CheckSecurity) RunRule(nodes []*yaml.Node, context model.RuleFunctionCo
drDoc := context.DrDocument.V3Document
globalSecurity := drDoc.Security

for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
path := pathPairs.Key()
pathItem := pathPairs.Value()
for opPairs := pathItem.GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()
opType := opPairs.Key()

if !slices.Contains(methods, opType) {
continue
}
if drDoc.Paths != nil && drDoc.Paths.PathItems != nil {

var opNode *yaml.Node
var op *drV3.Operation

switch opType {
case v3.GetLabel:
opNode = pathPairs.Value().Value.GoLow().Get.KeyNode
op = pathPairs.Value().Get
case v3.PutLabel:
opNode = pathPairs.Value().Value.GoLow().Put.KeyNode
op = pathPairs.Value().Put
case v3.PostLabel:
opNode = pathPairs.Value().Value.GoLow().Post.KeyNode
op = pathPairs.Value().Post
case v3.DeleteLabel:
opNode = pathPairs.Value().Value.GoLow().Delete.KeyNode
op = pathPairs.Value().Delete
case v3.OptionsLabel:
opNode = pathPairs.Value().Value.GoLow().Options.KeyNode
op = pathPairs.Value().Options
case v3.HeadLabel:
opNode = pathPairs.Value().Value.GoLow().Head.KeyNode
op = pathPairs.Value().Head
case v3.PatchLabel:
opNode = pathPairs.Value().Value.GoLow().Patch.KeyNode
op = pathPairs.Value().Patch
case v3.TraceLabel:
opNode = pathPairs.Value().Value.GoLow().Trace.KeyNode
op = pathPairs.Value().Trace
}
for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
path := pathPairs.Key()
pathItem := pathPairs.Value()
for opPairs := pathItem.GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()
opType := opPairs.Key()

if opValue.Security == nil && globalSecurity == nil {
if !slices.Contains(methods, opType) {
continue
}

result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` was not defined for path `%s` in method `%s`", path, opType)),
StartNode: opNode,
EndNode: opNode,
Path: op.GenerateJSONPath(),
Rule: context.Rule,
var opNode *yaml.Node
var op *drV3.Operation

switch opType {
case v3.GetLabel:
opNode = pathPairs.Value().Value.GoLow().Get.KeyNode
op = pathPairs.Value().Get
case v3.PutLabel:
opNode = pathPairs.Value().Value.GoLow().Put.KeyNode
op = pathPairs.Value().Put
case v3.PostLabel:
opNode = pathPairs.Value().Value.GoLow().Post.KeyNode
op = pathPairs.Value().Post
case v3.DeleteLabel:
opNode = pathPairs.Value().Value.GoLow().Delete.KeyNode
op = pathPairs.Value().Delete
case v3.OptionsLabel:
opNode = pathPairs.Value().Value.GoLow().Options.KeyNode
op = pathPairs.Value().Options
case v3.HeadLabel:
opNode = pathPairs.Value().Value.GoLow().Head.KeyNode
op = pathPairs.Value().Head
case v3.PatchLabel:
opNode = pathPairs.Value().Value.GoLow().Patch.KeyNode
op = pathPairs.Value().Patch
case v3.TraceLabel:
opNode = pathPairs.Value().Value.GoLow().Trace.KeyNode
op = pathPairs.Value().Trace
}
pathItem.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
continue

}
if opValue.Security == nil && globalSecurity == nil {

result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` was not defined for path `%s` in method `%s`", path, opType)),
StartNode: opNode,
EndNode: opNode,
Path: op.GenerateJSONPath(),
Rule: context.Rule,
}
pathItem.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
continue

if len(opValue.Security) <= 0 && globalSecurity != nil &&
(globalSecurity[0].Value.Requirements == nil || globalSecurity[0].Value.Requirements.Len() <= 0) {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` is empty for path `%s` in method `%s`", path, opType)),
StartNode: opNode,
EndNode: opNode,
Path: op.GenerateJSONPath(),
Rule: context.Rule,
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}

if !nullable && len(opValue.Security) >= 1 {
for i := range opValue.Security {
if opValue.Security[i].Value.Requirements == nil || opValue.Security[i].Value.Requirements.Len() <= 0 {
securityNode := opValue.Security[i].Value.GoLow().Requirements.ValueNode
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` has null elements for path `%s` in method `%s`", path, opType)),
StartNode: securityNode,
EndNode: securityNode,
Path: opValue.Security[i].GenerateJSONPath(),
Rule: context.Rule,
if len(opValue.Security) <= 0 && globalSecurity != nil &&
(globalSecurity[0].Value.Requirements == nil || globalSecurity[0].Value.Requirements.Len() <= 0) {
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` is empty for path `%s` in method `%s`", path, opType)),
StartNode: opNode,
EndNode: opNode,
Path: op.GenerateJSONPath(),
Rule: context.Rule,
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}

if !nullable && len(opValue.Security) >= 1 {
for i := range opValue.Security {
if opValue.Security[i].Value.Requirements == nil || opValue.Security[i].Value.Requirements.Len() <= 0 {
securityNode := opValue.Security[i].Value.GoLow().Requirements.ValueNode
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("`security` has null elements for path `%s` in method `%s`", path, opType)),
StartNode: securityNode,
EndNode: securityNode,
Path: opValue.Security[i].GenerateJSONPath(),
Rule: context.Rule,
}
pathItem.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
continue
}
pathItem.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
continue
}
}
}
Expand Down
48 changes: 25 additions & 23 deletions functions/owasp/define_error_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,37 @@ func (cd DefineErrorDefinition) RunRule(_ []*yaml.Node, context model.RuleFuncti

func processCodes(codes []string, drDoc *v3.Document, context model.RuleFunctionContext) []model.RuleFunctionResult {
var results []model.RuleFunctionResult
for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
for opPairs := pathPairs.Value().GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()
if drDoc.Paths != nil && drDoc.Paths.PathItems != nil {
for pathPairs := drDoc.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
for opPairs := pathPairs.Value().GetOperations().First(); opPairs != nil; opPairs = opPairs.Next() {
opValue := opPairs.Value()

responses := opValue.Responses.Codes
seen := make(map[string]bool)
responses := opValue.Responses.Codes
seen := make(map[string]bool)

var node *yaml.Node
var node *yaml.Node

for respPairs := responses.First(); respPairs != nil; respPairs = respPairs.Next() {
respCode := respPairs.Key()
if slices.Contains(codes, respCode) {
seen[respCode] = true
for respPairs := responses.First(); respPairs != nil; respPairs = respPairs.Next() {
respCode := respPairs.Key()
if slices.Contains(codes, respCode) {
seen[respCode] = true
}
}
}
node = opValue.Value.GoLow().Responses.KeyNode
node = opValue.Value.GoLow().Responses.KeyNode

if len(seen) <= 0 {
code := strings.Join(codes, "`, `")
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing one of `%s` response codes", code)),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("%s.%s", opValue.GenerateJSONPath(), "responses"),
Rule: context.Rule,
if len(seen) <= 0 {
code := strings.Join(codes, "`, `")
result := model.RuleFunctionResult{
Message: vacuumUtils.SuppliedOrDefault(context.Rule.Message,
fmt.Sprintf("missing one of `%s` response codes", code)),
StartNode: node,
EndNode: node,
Path: fmt.Sprintf("%s.%s", opValue.GenerateJSONPath(), "responses"),
Rule: context.Rule,
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
opValue.AddRuleFunctionResult(base.ConvertRuleResult(&result))
results = append(results, result)
}
}
}
Expand Down
Loading

0 comments on commit 2fffb5c

Please sign in to comment.