Cross Site Request Forgery in Echo Go with Bearer Tokens
Cross Site Request Forgery in Echo Go with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) in the Echo Go framework when Bearer Tokens are used centers on how authentication tokens are carried in requests and how state-changing endpoints are protected. In Echo Go, APIs commonly rely on HTTP Authorization headers with Bearer Tokens to identify users. If state-changing routes (POST, PUT, DELETE) validate only the presence of a valid Bearer Token and do not enforce additional CSRF defenses, an attacker can trick a logged-in user’s browser into issuing unwanted authenticated requests from the victim’s session.
Consider an Echo Go route that transfers funds using a bearer-only check:
func transfer(c echo.Context) error {
token := c.Request().Header.Get("Authorization")
if token == "" || !isValidBearer(token) {
return c.String(http.StatusUnauthorized, "unauthorized")
}
// perform transfer based on form values
return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
}
Because the route relies solely on the Authorization header, a forged request initiated from another origin (e.g., an image tag or form submission on a malicious site) will still carry the user’s Bearer Token if the user’s session cookie is sent automatically by the browser. Echo Go does not provide built-in CSRF middleware; developers must implement synchronizer token patterns or SameSite cookie attributes themselves. Without anti-CSRF tokens or explicit origin checks, an attacker can craft a request such as:
<form action="https://api.example.com/transfer" method="POST"> <input type="hidden" name="account" value="attacker_account" /> <input type="hidden" name="amount" value="9999" /> <button>Click for a prize</button> </form>
If the victim’s browser automatically includes the Bearer Token via the Authorization header (for example, set by JavaScript before navigation or via a custom header-prefetch mechanism), the server may mistakenly treat the forged request as legitimate. Another vector involves JSON-based APIs consumed by browser JavaScript that inadvertently expose the Authorization token via insecure storage or cross-origin requests, enabling malicious sites to influence authenticated actions. CSRF against Bearer Tokens is less common than cookie-based sessions, but it remains viable when tokens are stored in a manner that the browser can automatically include, such as in cookies without the SameSite attribute or when custom headers are set globally by shared client code.
Compounded risks include insecure direct object references (BOLA/IDOR) when the token identifies a subject that the attacker can guess or iterate over, and improper input validation that may allow header manipulation. The 12 parallel checks in middleBrick include Authentication and BOLA/IDOR specifically to surface such combinations, helping to detect when token-based authentication lacks complementary CSRF controls. Developers should treat Bearer Tokens as credentials that must be protected from automatic browser inclusion and should combine token validation with CSRF mitigations rather than relying on token secrecy alone.
Bearer Tokens-Specific Remediation in Echo Go — concrete code fixes
Remediation for CSRF with Bearer Tokens in Echo Go focuses on preventing the browser from automatically issuing authenticated requests to state-changing endpoints. The most robust approach is to avoid storing Bearer Tokens in locations the browser manages for cross-origin requests, and to enforce strict same-site and anti-CSRF practices.
A concrete code example of a vulnerable setup:
func login(c echo.Context) error {
// After verifying credentials, set a Bearer Token in a cookie
// This is vulnerable to CSRF if SameSite is not set and path allows cross-origin use
cookie := &http.Cookie{
Name: "auth_token",
Value: generateToken(),
Path: "/",
HttpOnly: true,
Secure: true,
// Missing SameSite and explicit CSRF token
}
c.SetCookie(cookie)
return c.JSON(http.StatusOK, map[string]string{"token": "returned"})
}
And a route that trusts the cookie header as a bearer token without CSRF protection:
func updateEmail(c echo.Context) error {
token := c.Request().Header.Get("Authorization")
if token == "" {
// fallback to cookie if Authorization header not provided
cookie, err := c.Cookie("auth_token")
if err != nil {
return c.String(http.StatusUnauthorized, "unauthorized")
}
token = "Bearer " + cookie.Value
}
// process update
return c.NoContent(http.StatusOK)
}
To remediate, apply the following patterns:
- Use the SameSite cookie attribute to prevent cross-site cookie submission:
cookie := &http.Cookie{
Name: "auth_token",
Value: generateToken(),
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode, // or Lax if needed for top-level navigations
}
c.SetCookie(cookie)
- Require the Authorization header for state-changing methods and avoid automatic fallback to cookies for bearer contexts. If you must support cookies, validate the Origin and Referer headers or use an anti-CSRF token stored in a separate, SameSite cookie:
func csrfMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Expect a custom header for state-changing requests
if c.Request().Method == http.MethodPost || c.Request().Method == http.MethodPut || c.Request().Method == http.MethodDelete {
reqToken := c.Request().Header.Get("X-CSRF-Token")
sessionToken := getSessionToken(c) // retrieve from secure, SameSite cookie
if reqToken == "" || reqToken != sessionToken {
return c.String(http.StatusForbidden, "invalid csrf token")
}
}
return next(c)
}
}
- Do not store Bearer Tokens in localStorage or other JavaScript-accessible storage that can be read by cross-origin scripts; prefer secure, HttpOnly, SameSite cookies for session tokens, and keep actual bearer usage for non-browser clients where CSRF risk is managed differently.
By combining SameSite cookies, strict header-based bearer validation, and explicit CSRF tokens for privileged actions, you reduce the likelihood that an attacker can force an authenticated Echo Go client to perform unwanted operations. middleBrick’s checks for Authentication and Property Authorization help ensure that token handling and permission checks align with these patterns, providing findings and remediation guidance tailored to your API’s configuration.