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>
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.
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.