Addressing Harbor Registry Vulnerability with 42Crunch

Hot from the press! There is a mass assignment vulnerability in the Harbor registry. Mass assignment is entry A6 on the OWASP API Security Top 10 list.

A6 is described in the OWASP API Security Top 10 as:

An API endpoint is vulnerable if it automatically converts client parameters into internal object properties without considering the sensitivity and the exposure level of these properties. This could allow an attacker to update object properties that they should not have access to.

As mentioned in the CVE report, this is exactly what happened. The API, written in Go, directly decodes the data sent to the API like this:

if err := ua.DecodeJSONReq(&user); err != nil

The User object contains the following:

The key here is the HasAdminRole element: if a hacker can set this to true, it’s basically Game Over. Harbor is an open source project , we therefore have access to the source code. The developers did a good job on the documentation here, which gives us the JSON property name to set (has_admin_role).

How to prevent with the 42Crunch platform ?

You can use the 42Crunch platform to stop such attacks by defining an OpenAPI based whitelist: only what is in the defined schema will get accepted.

In order to build the ultimate whitelist, you can use the Audit service to analyze your API definition and give you an audit score, which indicates the security quality of your OpenAPI file.

  • If the operation POST /api/users had no JSON schema, we would have flagged that as a major issue.
  • If a schema has been defined but poorly (no patterns, no min, no max, additionalProperties allowed), we would have flagged that too.

Once the score is satisfactory, you can use directly the OpenAPI file to configure our API firewall.  Imagine you have defined the JSON schema for POST /api/users to be:

 

 

 

 

 

 

 

 

At runtime, a call such as the following would work just fine:

POST /api/users

{
  "username": "newuser",
  "email": "myemail@foo.com",
  "realname": "myname",
  "password": "Password1\u0021",
  "comment": "null"
}

However, posting the following would be blocked automatically, since it does not conform to the schema:

{
  "username": "newuser",
  "email": "myemail@foo.com",
  "realname": "myname",
  "password": "Password1\u0021",
  "comment": "null",
  "has_admin_role": true
}

What else can we do ?

The schema above is actually quite poor. It does not describe the format of the data. As an example, the email is defined as a string. Instead it should be defined like this:

"email": {
   "type": "string",
   "minLength": 15,
   "maxLength": 50,
   "pattern": "^([a-zA-Z0-9_\\\\-\\\\.]+)%40([a-zA-Z0-9_\\\\-\\\\.]+)\\\\.([a-zA-Z]{2,5})$"
 },
 ...
 "required": [
   "username",
   "email",
   ...
 ]

If the email property is specified as above, not only do we ensure the email is present, we also validate the string in the request against the given pattern as well as minimal and maximal lengths, closing the door on attacks such as injections or overflows.

If you want to see how we would protect your APIs, request a demo now!

For news on all things API – visit APIsecurity.io! Sign up for the weekly newsletter and try our security audit for free!