Why
The current exception handling allows for a non-obvious path for information to leak to the client from the server side.
For example:
LookupError(f"{user_id} not found in User table")
leaks the variable user_id
to the client.
Being able to review the server logs for errors to improve products is a great feature.
However, the exceptions today need to be narrowly crafted to avoid leaking information to the client side which diminishes their power.
Having to consider how each exception could be exploited by a bad actor is a bit exhausting and non-obvious. Capturing all exceptions reduces the power of server logs ability to filter by errors.
Proposal
Do not forward
Simply do not send exception information to the client.
I lean towards the automatic Published
version of these options as it is more fool proof and maintains existing stdout
behavior.
- Flag
Provide a flag for the app that stops the forwarding of exceptions to the client side.
- Published
Follow the print
statement method and disable exception forwarding to the client in Published environments.
Opaque exception information
Re-raise exceptions with session id
before sending them to the client to allow clients to reference their error in a meaningful manner to aid in diagnosing issues.
- Exception is raised
- Server logs exception as normal
- Server re-raises as
Exception(anvil.server.get_session_id())
before sending to the client-side.
5 Likes
Along with the Exception type and value, the traceback is also sent to the client. This includes file names and line numbers of the error stack.

Unlike exception messages, this information you don’t have a choice of being included in the Exception.
Are you sure this is sent both while running from the IDE and while running in production?
Yes. Included app.environment
in the raised exception below:
Debug:
Published:

How that can be used? Let me leak another user_id not found in User table - jbhsgjsklxnxbskgsjvbxmxcbvdcfs. So what? I bet LOTS of projects have ServerModule1.py and ServerModule2.py and ServerModule3.py… how should I profit from that knowledge?
Hey @and.obn,
The more information that is exposed, the larger the attack surface becomes and the easier it is to gain access.
The easy analogy is passwords.
- You know nothing about the user or the use
- You know the use is on site
example.com
- You know the password from
example.com
must be 12 characters and can’t include special characters
- You can view the user’s social media accounts
- You know their passwords from other websites
- You went to high school with the user and remember
- Their dog’s name
- Their mothers name
- Their favorite teacher
- Their high school sweetheart
- The street they lived on
- …
As a malicious actor the more information on your target, the higher your changes of success.
So, your example of who cares about leaking ServerModule1.py
. Well, yeah, you are right. ServerModlue1.py
is a reasonable form of obfuscation. Even better would be to just rename all modules with a random sting, bfb18538.py
and worse would be the maintainable UserAuthentication.py
or the unavoidable libraries, requests
, six
.
Perhaps you broadcast that you are using a library that has a vulnerability that could be exploited.
Who cares about leaking jbhsgjsklxnxbskgsjvbxmxcbvdcfs
?
Well, now I know:
- that it is a
user_id
- that likely all
user_id
s are 30, lower-case letters, long
- containing chars:
bcdfghjklmnsvx
- based on key frequency, likely keyboard mashed with strong aversion to upper row characters.
- that is it my
user_id
and it is valid
- I can probe server calls with my valid
user_id
and an invalid id to try and trigger errors and gain access to poorly protected endpoints.
- I could check if my
user_id
is a common hash of something like my email address, maybe I can spoof other accounts.
4 Likes
I agree with this. For production apps, the actual server-side exception details should be as transparent as possible in the anvil logs, and as opaque as possible for the Client (basically the repr
of the exception).
Django deals with this with an environment DEBUG flag, which seems pretty reasonable and lends well to the Anvil debug environment framework…