Data Exposure in Fiber (Go)
Data Exposure in Fiber with Go — how this specific combination creates or exposes the vulnerability
When building APIs with Fiber in Go, data exposure often stems from how route handlers serialize and transmit structured data. Unlike some frameworks that encourage strict separation, it is easy in Go to pass internal structures directly to JSON serialization without filtering sensitive fields. Because JSON tags control only serialization and do not enforce access control, omitting sensitive fields from serialization logic or relying on frontend filtering leads to unintended data disclosure.
Consider a typical handler that returns a user record:
//go:generate go run github.com/gofiber/fiber/v2/cmd/fiber/v2@latest init
package main
import (
"github.com/gofiber/fiber/v2"
)
type User struct {
ID uint `json:\"id\"`
Email string `json:\"email\"`
Password string `json:\"-\"` // intended to omit from JSON
APIKey string `json:\"api_key\"`
}
func main() {
app := fiber.New()
app.Get("/users/:id", func(c *fiber.Ctx) error {
// Simulated DB fetch
user := User{
ID: 1,
Email: "[email protected]",
Password: "supersecret",
APIKey: "sk_live_abc123",
}
return c.JSON(user)
})
app.Listen(":3000")
}
In this example, the Password field uses json:"-" to exclude it from serialization, and APIKey is explicitly included. If the developer forgets to remove APIKey from the response or mistakenly includes it during refactoring, the live API will leak credentials to any client. Similarly, structs that embed internal metadata (such as database IDs or version fields) can unintentionally expose implementation details when returned directly.
Data exposure in this context also relates to how responses are scoped to the requester. Without proper authorization checks (e.g., ensuring users can only view their own data), an endpoint like /users/:id may return information belonging to other users. This intersects with BOLA/IDOR considerations, but the root cause is often a handler that serializes a full data model without applying field-level or row-level filtering. Even when using struct embedding or helper serialization functions, missing checks can result in sensitive fields such as tokens, hashes, or internal flags being included in the JSON payload.
The use of pointers and omitempty can also introduce subtle exposure risks. For example:
type SafeUser struct {
ID uint `json:\"id\"`
Email string `json:\"email\"`
Token *string `json:\"token,omitempty\"`
}
If Token is a pointer that is non-nil in some code paths, it will be included in the response. In Go, zero values are often omitted with omitempty, but pointers require explicit nil checks. If the handler does not carefully manage token lifetimes and sets them conditionally, the field may appear in responses when it should remain hidden.
Because middleBrick tests the unauthenticated attack surface, it can detect whether sensitive fields are present in JSON responses for public endpoints. Findings typically highlight specific fields (e.g., api_key, password_hash) returned without access controls and recommend removing them from serialization or enforcing strict authorization before data transmission.
Go-Specific Remediation in Fiber
Remediation centers on disciplined struct design, centralized serialization, and explicit authorization. Define separate response structs that include only the fields intended for the client. This prevents accidental inclusion of sensitive fields even if the domain model changes.
Example of a safe, dedicated response struct:
//go:generate go run github.com/gofiber/fiber/v2/cmd/fiber/v2@latest init
package main
import (
"github.com/gofiber/factor/v2"
)
type User struct {
ID uint `json:\"id\"`
Email string `json:\"email\"`
Password string `json:\"-\"`
APIKey string `json:\"-\"`
}
type UserPublic struct {
ID uint `json:\"id\"`
Email string `json:\"email\"`
}
func currentUser(c *fiber.Ctx) error {
// In practice, derive userID from authenticated session
user, err := findUserByID(c.Params(\"id\"))
if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{\"error\": \"not found\"})
}
return c.JSON(UserPublic{ID: user.ID, Email: user.Email})
}
func findUserByID(id string) (User, error) {
// Simulated DB lookup
return User{
ID: 1,
Email: "[email protected]",
Password: "supersecret",
APIKey: "sk_live_abc123",
}, nil
}
This pattern ensures that only UserPublic is serialized. The sensitive fields on User are tagged with - or omitted, and no accidental refactoring will expose them because they are not present in the response struct.
For endpoints that must return variable fields, use selective population or a whitelist approach. With maps, you can explicitly set allowed keys:
func getUserFields(c *fiber.Ctx) error {
user, err := findUserByID(c.Params(\"id\"))
if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{\"error\": \"not found\"})
}
// Explicitly allowlisted fields
response := map[string]interface{}{
\"id\": user.ID,
\"email\": user.Email,
}
return c.JSON(response)
}
Authorization should be checked before serialization. Even when using public structs, verify that the requesting user is permitted to view the target resource:
func getUserProfile(c *fiber.Ctx) error {
userID := c.Params(\"id\")
// Assume getAuthenticatedUserID returns the requester's user ID
requesterID := getAuthenticatedUserID(c)
if requesterID != userID {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{\"error\": \"forbidden\"})
}
user, err := findUserByID(userID)
if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{\"error\": \"not found\"})
}
return c.JSON(UserPublic{ID: user.ID, Email: user.Email})
}
These practices align with checks that middleBrick performs, such as verifying that sensitive fields are not returned on public endpoints and that responses are scoped to the requesting user. By combining strict struct definitions, centralized data transformations, and per-request authorization, you reduce the likelihood of accidental data exposure in Fiber Go services.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |