GuardAPI Logo
GuardAPI

Fix Shadow API Exposure in TurboGears

Shadow APIs are the silent killers of enterprise security. In TurboGears, the 'Object Dispatch' system is a double-edged sword: it makes routing intuitive but often leads to 'accidental exposure' of internal or legacy methods. If you decorate a method with @expose() and leave it in your controller tree, you've just handed an attacker a map to your hidden attack surface. This guide targets the elimination of undocumented endpoints and the hardening of the dispatch mechanism.

The Vulnerable Pattern

from tg import expose, TGController

class APIController(TGController): @expose(‘json’) def public_data(self): return dict(status=‘ok’, data=‘public’)

@expose('json')
def legacy_debug_endpoint(self, **kw):
    # SHADOW API: Forgotten debug tool exposed to the public
    # Attacker can fuzz this and find sensitive system state
    return dict(env='prod', db_status='connected', internal_id='0x4421')</code></pre>

The Secure Implementation

To kill Shadow APIs in TurboGears, you must master the Dispatcher. First, audit your controller tree for any method using @expose() that isn't documented in your API schema; if it's not needed by the frontend, strip the decorator. Second, use the underscore prefix convention (_method_name) for any helper functions; TurboGears dispatch ignores these by default. Third, use the @restrict decorator to prevent 'Verb Tunneling'—don't let GET requests hit state-changing logic. Finally, always wrap sensitive endpoints with @require(predicates...) to ensure that even if an endpoint is discovered, it cannot be exploited without valid, high-privilege credentials.

from tg import expose, TGController, restrict, require
from repoze.what import predicates

class APIController(TGController): @expose(‘json’) @restrict(‘GET’) def public_data(self): return dict(status=‘ok’, data=‘public’)

# FIX 1: Remove @expose from internal logic
def _internal_helper(self):
    return "Not reachable via URL"

# FIX 2: Explicitly require authentication and restrict verbs
@expose('json')
@restrict('POST')
@require(predicates.has_permission('admin'))
def administrative_task(self, **kw):
    return dict(result='success')</code></pre>
System Alert • ID: 3822
Target: TurboGears API
Potential Vulnerability

Your TurboGears API might be exposed to Shadow API Exposure

74% of TurboGears apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.