Replay Attack in Echo Go
How Replay Attack Manifests in Echo Go
In Echo Go, a replay attack exploits the framework's default statelessness and lack of built-in request uniqueness validation. An attacker captures a legitimate request (e.g., a funds transfer or order placement) and resubmits it, causing the server to process the same action multiple times. This is particularly severe in state-changing operations (POST/PUT/DELETE) where Echo handlers directly mutate state without nonce or timestamp checks.
Echo Go-Specific Attack Patterns:
- Idempotency Key Bypass: Echo does not enforce or validate
Idempotency-Keyheaders by default. A vulnerable endpoint might look like:
e.POST("/transfer", func(c echo.Context) error {
var req TransferRequest
if err := c.Bind(&req); err != nil {
return c.JSON(400, map[string]string{"error": "invalid request"})
}
// Process transfer without checking for duplicate requests
return processTransfer(req)
})An attacker can replay this exact HTTP request (with same body/headers) and trigger multiple transfers.
- Timestamp/Nonce Absence: Echo's context (
c) provides request headers viac.Request().Header, but handlers often omit validation ofDate,X-Nonce, orX-Timestampheaders. Without server-side storage to track used nonces, replay is trivial. - JWT Replay: If Echo uses JWT middleware (like
jwt-middleware) withoutjti(JWT ID) validation, a stolen token can be reused until expiration.
Real-World Impact: In an Echo Go banking API, a captured POST /api/v1/payment request with JSON body {"amount":100,"to":"attacker"} could be replayed 10 times, draining the victim's account. This maps to OWASP API Top 10:2023 API7:2023 – Server Side Request Forgery (SSRF) (if replay leads to internal SSRF) and API4:2023 – Unrestricted Resource Consumption (via repeated expensive operations).
Echo Go-Specific Detection
Detecting replay vulnerabilities in Echo Go requires testing for duplicate request acceptance. Since Echo is a black-box framework, you must inspect runtime behavior without source code. middleBrick automates this by:
- Resubmitting Captured Requests: After an initial scan, middleBrick replays identical requests (preserving headers/body) and compares responses. If the second request returns
200 OKwith a new resource ID or state change (e.g., new database entry), replay is possible. - Header Variation Testing: It tests if adding
Idempotency-Key: <random>changes behavior. Echo endpoints that ignore this header are vulnerable. - Timestamp Drift Analysis: middleBrick submits requests with
X-Timestampheaders set to past times. If accepted, the endpoint lacks temporal validation.
Manual Detection Steps for Echo Go:
- Use a proxy (Burp Suite) to capture a state-changing request.
- Replay it via
curlor Burp Repeater without modification:
curl -X POST https://api.example.com/transfer \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{"amount":100,"to":"attacker"}'- Check if the server creates duplicate resources (e.g., two transaction IDs). In Echo, this often means the handler's database insert runs unconditionally.
- Inspect Echo middleware chain (if source available) for missing nonce validation. Look for
e.Use()calls that don't include replay protection.
middleBrick's Report: A scan of an Echo Go API would flag replay issues under the Authentication or Rate Limiting categories, with a finding like: "Endpoint accepts duplicate requests without idempotency key validation. Attackers can replay captured requests to cause unintended state changes." The report includes the exact request that was replayed and the duplicated response evidence.
Echo Go-Specific Remediation
Remediation in Echo Go requires implementing request uniqueness validation at the middleware or handler level. Echo's middleware ecosystem does not include built-in replay protection, so custom code is necessary.
1. Idempotency-Key Middleware
Create middleware that stores processed keys in a fast cache (Redis/Memcached) with a TTL. Echo's echo.MiddlewareFunc signature allows access to echo.Context:
package middleware
import (
"github.com/labstack/echo/v4"
"github.com/go-redis/redis/v8"
"crypto/sha256"
"encoding/hex"
"time"
"context"
)
func ReplayProtection(rdb *redis.Client) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
key := c.Request().Header.Get("Idempotency-Key")
if key == "" {
// Generate key from method+path+body hash
body, _ := io.ReadAll(c.Request().Body)
c.Request().Body = io.NopCloser(bytes.NewBuffer(body))
hash := sha256.Sum256(body)
key = hex.EncodeToString(hash[:])
}
ctx := context.Background()
exists, err := rdb.SetNX(ctx, "replay:"+key, "1", 24*time.Hour).Result()
if err != nil || !exists {
return c.JSON(409, map[string]string{
"error": "duplicate request (replay detected)",
"idempotency_key": key,
})
}
return next(c)
}
}
}Apply globally: e.Use(middleware.ReplayProtection(redisClient))
2. Timestamp + Nonce Validation
For stateless validation, use a signed timestamp-nonce pair. Echo handlers can verify using HMAC:
e.POST("/payment", func(c echo.Context) error {
ts := c.Request().Header.Get("X-Timestamp")
nonce := c.Request().Header.Get("X-Nonce")
sig := c.Request().Header.Get("X-Signature")
// Verify timestamp is recent (e.g., < 5 min)
t, _ := time.Parse(time.RFC3339, ts)
if time.Since(t) > 5*time.Minute {
return c.JSON(400, map[string]string{"error": "stale request"})
}
// Verify signature: HMAC(secret, ts+nonce)
expected := hmac.New(sha256.New, []byte(secret))
expected.Write([]byte(ts + nonce))
if !hmac.Equal(expected.Sum(nil), []byte(sig)) {
return c.JSON(401, map[string]string{"error": "invalid signature"})
}
// Check nonce uniqueness in cache (Redis) to prevent replay within window
// ... (similar to Idempotency-Key check)
return processPayment(c)
})3. JWT jti Validation
If using JWT, validate the jti claim against a denylist (Redis) after token revocation. Echo's JWT middleware (e.g., github.com/golang-jwt/jwt/v5) can be extended:
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if !token.Claims.Valid() {
return nil, errors.New("invalid claims")
}
claims := token.Claims.(jwt.MapClaims)
jti := claims["jti"].(string)
// Check Redis denylist: if rdb.Exists("jwt:denylist:"+jti) { return nil }
return []byte(secret), nil
})Compliance Mapping: These fixes address OWASP API Top 10:2023 API2:2023 – Broken Authentication (weak session handling) and API4:2023 – Unrestricted Resource Consumption (replay as resource exhaustion). They also support PCI-DSS requirement 8.2 (unique authentication per session) and HIPAA §164.312(a)(2)(i) (transmission security).
Testing Remediation: After applying fixes, rescan with middleBrick. The replay finding should disappear. Use the CLI to verify:
middlebrick scan https://your-echo-api.com --check replayProactive scanning in CI/CD (via GitHub Action) ensures new Echo endpoints include replay protection before deployment.
Conclusion
Replay attacks in Echo Go exploit the framework's minimal default security, targeting any endpoint that changes state without request uniqueness checks. Detection requires black-box testing for duplicate request acceptance—something middleBrick automates in its 12 parallel checks. Remediation demands explicit Echo middleware for idempotency keys, timestamp-nonce validation, or JWT jti tracking. Given Echo's popularity for high-performance APIs, securing against replay is non-negotiable for financial, e-commerce, or any state-sensitive application.