A security flaw of moderate to high severity

Hi!

On the console an RPC request is displayed that actually leaks all data from datatables in profile.ts:

We can find e. g. the current user’s password hash and other data (e.g. e-mail) in the data listed on the console.

It is the same with the Anvil runtime.

George

@thetaghun the current logged in user ALWAYS has access to their row in the users table. Essentially there is no way to keep the currently logged in user from calling the anvil.users.get_user() and getting the table row.

Because of this:
Don’t use links in the users table, as the linked rows are also available to the client without a server side call. The real scary case is where you are linking to another row in the users table, think social network use case, as this can cascade and expose your entire table to a single authenticated user.

Don’t add any data to the users table that you don’t want the user to obtain. I add a UUID4 token in the users table which becomes their primary key in other tables that I don’t want them to have access to.

Because it is only the currently logged in user, leaking their hashed password is not really an issue. I would say that the real data leak in this case is obtaining information about how passwords are stored and the salt, hash method. But, this is readily available in the GitHub repo for Anvil anyways.

You can read more about the security in the users table here: Security of users table

Are you seeing other information leaked beyond what the currently logged in user should have?

3 Likes

Dear Racer,

Thanks for the fast information!

I’ve got this solution eventually: since the profile.ts - I suppose - handles performance related matters (or maybe user profile related matters), I can unpackage the runtime, remove the relevant lines from the .ts code and package it back. (Some packaging issues may arise.) Then, this will not be seen at least in the runtime version. (I use the editor to create and test apps but these will be hosted elsewhere for different kinds of technical reasons that can’t be done if it is hosted on anvil.work servers. E.g. the same app runs on 2-3 different machines.)

Comment this is NOT just the users table but as long as I can see but ANY data may leak. MAY! I didn’t yet checked it thoroughly. Because these data are rather not to the browser console in any circumstance in my (40 years) experience.

(Btw, I studied the Anvil runtime’s code in fair detail because in the future some security additions may be necessary that currently can’t be done with Anvil. E. g. obfuscating or encrypting the generated code which is pretty secure currently since they added suspension to Skulpt and it uses closures in many ways that are extremely hard to catch and analyze the data, e. g. the running Python code in the browser. Because without suspension, in the browser a pretty pure, easy to read Python code could have been read and all internal data easy to access.)

What do you think of my above solution?

And thanks again!

George

@thetaghun

If you can demonstrate access to a table (that is not the user table) that is marked as client code has no access to this table, we would all be very interested!

Non-user table data can be leaked through a user row when linked to other tables.

All browser code is insecure and should be treated as such. It can be viewed and modified by a user. All of your data security logic should be on the server where you can make the determination of what data this request should have access to.

1 Like

Since I’ve been coding for a very long time, I have ideas how others may (occasionally) use a leaked hash to (incidentally) hack into a system using this hash only. It is not an option to hide such a hash: it must be done in time. (It is not of immediate urgency.)

Also, I think data exchange between the server and the client may be limited or encrypted in some ways. But I guess repacking the Anvil runtime is much easier. (If no issue comes up, it takes 3-5 mins. 15-180 mins otherwise.)

But the main point is this: while doing the final tests, I will need to check this. (I already checked the Network tab in Chrome Devtools and found nothing of use. But I didn’t inspected network packets yet if they contain any useful information. It will be done much later.)

Thx again for reply.

George

The only client that sees that hash is the one already authenticated. It appears in network responses while the user is logged in, not in the app’s public code. Traffic is encrypted, so an external attacker cannot read it in transit. If an attacker can control a logged-in browser, they already have the user’s session and can access everything the app provides, so the hash adds no new exposure.

Transport is encrypted (HTTPS), and Anvil provides app-level secret storage for server-side data. That protects information in transit and secrets kept on the server. It does not protect secrets included in client-side code or the downloaded bundle. Avoid placing sensitive values in client-side code; keep them on the server.

Client-side Python is transpiled to JavaScript (Skulpt) and delivered to the browser. You can rebuild or modify that runtime/bundle and ship a custom client. That can mitigate exposure but is not a substitute for removing secrets from client code. Keep sensitive checks and keys server-side.

Client code can call server functions you expose via anvil.server.call('name'). Only functions you expose are callable, so do not expose privileged endpoints.

The real security concern here is not the hash or code visible to an authenticated user, but the linked-row data from the Users table that can unintentionally expose related records, as @racersmith pointed out earlier. Properly controlling access to linked rows and restricting what’s returned to the client is essential.

1 Like

Dear Stefano,

Thank you for your in-depth answers.
If only the logged in users hash can be seen on the console, that is still a minor measure at least. I will take it that way. (There’s a lot more to do.)

I’m not planning to link data within the users row. My tables only refers to the users row.

The only flaw may be that the user using these data somehow may change his/her access to certain things that will be stored in the users table. (Still will need a really smart hacker. So, not an urgent matter either.)

George

That facility is offered to the application’s developer, not to the app’s users. See

If you ever find a way for the end-user to modify the protected (server-side-only) schema, security details, or source code, then you should contact Anvil directly, with the details. If it turned out to be a real security issue, instead of a “somehow” one, then I expect they’d fix it as quickly as possible.

This can also be an issue. Let’s say that you’re writing a social app where other users can comment on my posts, and the comment data table contains a link to the Users row of the author. If you send the comment row to the client so I can see their comment, you’ve also just sent their Users row to me. That gives me access to their Users data (and the Users data of anyone who comments on my posts), including their password hashes.

To avoid this you need to not use a linked reference to the Users table (or any table with sensitive information).

Hi!

Thanks for your answer.
Yes, I studies all possible Guides and the API. Every part of these. I also checked some forum articles I was able to find.

Well, “somehow” is how the hackers work.
I personally know a few key points of hacking, since I need to check such security details. Many are complex, a few are not. E. g. patching the network packets with a proxy server is a fairly easy approach. And for these reasons, later, I want to add hard code obfuscation and encryption to the code sent from the app server to the browser. These are compiled online after a page has been modified.

But also, I check every possible way I know how security may be compromised. Even just a little or just very seldom. This is a long term issue.

George

Hi!

Thanks for reminding me this issue.

I wasn’t precisely telling you how I refer (link) to the users table: not by using normal ways but using internal IDs. (Due to different reasons, I need to generate my own row IDs and not use the provided row ID.)

I think, this recent decision (born a few days ago), will solve such possible flaws.

Anyway, I will watch for such an issue in the future in the database.

George