45 ways to break an API server (negative tests with examples)

zvone187

zvone187

Posted on April 19, 2023

45 ways to break an API server (negative tests with examples)

As developers, we strive to write error-free code, but no one actually does so because...well, bugs. In order to catch those pesky bugs before they wreak havoc on our applications, we rely on automated testing. While positive tests ensure our code works as intended, negative tests play a crucial role in validating that our applications are robust enough to handle unexpected input and edge cases.

I'm working on Pythagora, an open source tool that writes automated integration tests by itself (well, with a bit of help from GPT-4) without you, the dev, having to write a single line of code. Basically, you can get from 0 to 80% code code coverage within 30 minutes (video).

We just created a feature that automatically generates negative tests from the entire test suite with a single command. While building that feature, I researched what are different ways one can break an API server to test if it handles errors gracefully so here it is - a comprehensive list of ways with which you can break your server, if it doesn't handle errors properly.

1. Empty or missing required fields

{
    "endpoint": "/api/users",
    "body": {
        "username": "",
        "email": ""
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

2. Invalid field values - exceeding character limits

{
    "endpoint": "/api/users",
    "body": {
        "username": "ThisIsAnIncrediblyLongUsernameThatExceedsTheCharacterLimit"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

3. Invalid field values - malformed data

{
    "endpoint": "/api/users",
    "body": {
        "email": "invalid-email@"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

4. Extra or irrelevant keys in the payload

{
    "endpoint": "/api/users",
    "body": {
        "username": "validuser",
        "extra_key": "irrelevant_value"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

5. Incorrect or invalid HTTP methods

{
    "endpoint": "/api/users/123",
    "body": {},
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

6. Invalid endpoint paths

{
    "endpoint": "/api/nonexistent_endpoint",
    "body": {},
    "method": "GET"
}
Enter fullscreen mode Exit fullscreen mode

7. Query parameters instead of using the request body in POST requests

{
    "endpoint": "/api/users?username=testuser",
    "body": {},
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

8. Missing or invalid authentication headers (e.g., API keys)

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Invalid API_KEY"
    }
}
Enter fullscreen mode Exit fullscreen mode

9. Incorrect data structure - array instead of an object

{
    "endpoint": "/api/users",
    "body": [
        "username": "testuser",
        "email": "test@example.com"
    ],
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

10. Incorrect data structure - object instead of an array

{
    "endpoint": "/api/users",
    "body": {
        "users": {
            "username": "testuser",
            "email": "test@example.com"
        }
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

11. JSON formatting issues - invalid Unicode characters

{
    "endpoint": "/api/users",
    "body": {
        "username": "test\uFFFFuser"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

12. Duplicate keys in the payload

{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser",
        "username": "duplicate"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

13. Invalid or unsupported content types (e.g., sending XML instead of JSON)

{
    "endpoint": "/api/users",
    "body": "<user><username>testuser</username><email>test@example.com</email></user>",
    "method": "POST",
    "headers": {
        "Content-Type": "application/xml"
    }
}
Enter fullscreen mode Exit fullscreen mode

14. Exceeding payload size limits

{
    "endpoint": "/api/users",
    "body": {
        "large_data": "A very large data string that exceeds the server's payload size limit..."
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

15. Invalid or expired authentication tokens

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer expired_token"
    }
}
Enter fullscreen mode Exit fullscreen mode

16. Using special characters in field values

{
    "endpoint": "/api/users",
    "body": {
        "username": "test!@#$%^&*()-user"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

17. Sending nested objects instead of simple key-value pairs

{
    "endpoint": "/api/users",
    "body": {
        "user": {
            "username": "testuser",
            "email": "test@example.com"
        }
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

18. Sending data in the wrong data type (e.g., string instead of integer)

{
    "endpoint": "/api/users",
    "body": {
        "age": "25"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

19. Sending null values for required fields

{
    "endpoint": "/api/users",
    "body": {
        "username": null
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

20. Using reserved keywords in field names

{
    "endpoint": "/api/users",
    "body": {
        "class": "user"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

21. Sending incomplete or malformed multipart file uploads

{
    "endpoint": "/api/upload",
    "body": {
        "file": "incomplete_file_data"
    },
    "method": "POST",
    "headers": {
        "Content-Type": "multipart/form-data"
    }
}
Enter fullscreen mode Exit fullscreen mode

22. Incorrect or missing URL encoding for special characters

{
    "endpoint": "/api/users?username=test user",
    "body": {},
    "method": "GET"
}
Enter fullscreen mode Exit fullscreen mode

23. Sending the request body in GET requests

{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser"
    },
    "method": "GET"
}
Enter fullscreen mode Exit fullscreen mode

24. Invalid date or time formats

{
    "endpoint": "/api/users",
    "body": {
        "birthdate": "01-25-1990"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

25. Using non-ASCII characters in field names

{
    "endpoint": "/api/users",
    "body": {
        "üsername": "testuser"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

26. Sending deeply nested objects

{
    "endpoint": "/api/users",
    "body": {
        "user": {
            "profile": {
                "details": {
                    "nested": "too_deep"
                }
            }
        }
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

27. Using non-printable or control characters in field values

{
    "endpoint": "/api/users",
    "body": {
        "username": "test\u0008user"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

28. Sending the same field multiple times with different values

{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser",
        "username": "different"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

29. Missing or invalid content-length headers for request bodies

{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser"
    },
    "method": "POST",
    "headers": {
        "Content-Length": "invalid"
    }
}
Enter fullscreen mode Exit fullscreen mode

30. Using spaces or special characters in field names

{
    "endpoint": "/api/users",
    "body": {
        "user name": "testuser"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

31. Sending invalid or malformed JSONP callbacks

{
    "endpoint": "/api/users?callback=invalid(callback)",
    "body": {},
    "method": "GET"
}
Enter fullscreen mode Exit fullscreen mode

32. Sending the payload as a single string instead of key-value pairs

{
    "endpoint": "/api/users",
    "body": "username=testuser&email=test@example.com",
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

33. Sending boolean values as strings (e.g., "true" instead of true)

{
    "endpoint": "/api/users",
    "body": {
        "active": "true"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

34. Using non-standard HTTP methods (e.g., PATCH, CONNECT)

{
    "endpoint": "/api/users/123",
    "body": {
        "username": "updateduser"
    },
    "method": "PATCH"
}
Enter fullscreen mode Exit fullscreen mode

35. Sending unsupported HTTP version numbers

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "httpVersion": "HTTP/3.0"
}
Enter fullscreen mode Exit fullscreen mode

36. Sending multiple authentication headers (e.g., both API key and token)

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer token_value",
        "API-Key": "api_key_value"
    }
}
Enter fullscreen mode Exit fullscreen mode

37. Sending unnecessary or invalid CORS headers

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Access-Control-Allow-Origin": "*"
    }
}
Enter fullscreen mode Exit fullscreen mode

38. Sending conflicting query parameters and request body data

{
    "endpoint": "/api/users?username=testuser",
    "body": {
        "username": "different_user"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

39. Using non-standard characters in authentication header values

{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer t@ken_value"
    }
}
Enter fullscreen mode Exit fullscreen mode

40. Sending negative numbers for fields that should only accept positive values

{
    "endpoint": "/api/users",
    "body": {
        "age": -25
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

41. Sending timestamps in the future or past beyond expected range

{
    "endpoint": "/api/users",
    "body": {
        "birthdate": "01-25-1800"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

42. Using HTML, JavaScript, or SQL code in field values to attempt code injection

{
    "endpoint": "/api/users",
    "body": {
        "username": "<script>alert('test')</script>"
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

43. Using different character encodings in the payload (e.g., UTF-8, UTF-16)

{
    "endpoint": "/api/users",
    "body": {
        "username": "téstuser"
    },
    "method": "POST",
    "headers": {
        "Content-Type": "application/json; charset=UTF-16"
    }
}
Enter fullscreen mode Exit fullscreen mode

44. Sending arrays with mixed data types

{
    "endpoint": "/api/users",
    "body": {
        "values": [1, "string", true]
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

45. Sending field values as arrays or objects instead of simple data types (e.g., string, number)

{
    "endpoint": "/api/users",
    "body": {
        "username": ["testuser"]
    },
    "method": "POST"
}
Enter fullscreen mode Exit fullscreen mode

That's it. I hope this list gave you new ideas to test and protect your server.

If you found this post valuable, it would mean the world to me if you could support us by starring Pythagora Github repo.

And, if you try it out, please let us know your feedback, we're happy to hear it.

💖 💪 🙅 🚩
zvone187
zvone187

Posted on April 19, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related