Is this true? If I had important values in the module script, can a hacker edit them? Or just view them?
Yes exploiters can manipulate variables stored in a ModuleScript. This doesn’t change from if you were to use a LocalScript since exploiters can modify the client environment including variables in it.
The issue here isn’t what type of script you’re using, this just changes the execution context: in the case of a LocalScript it can execute independently but ModuleScripts will execute as in when the require function is used and will return the same instance back each subsequent require on the same environment. In both cases, code that needs to execute/consume memory will do so the same way for both script types. The main thing is looking at the code itself and your code architecture.
It’s ok to hold important values on the client but if you’re using them for any game critical system or something that can affect the gameplay of others, your source of truth should be the server - meaning the server should hold a true copy of what those values should be rather than accepting whatever the client gives it as fact (excludes systems that require client authority, in which you change your strategy from validation to sanitisation or anything more appropriate).
Like in my case, I have a mission GUI. Where you can do missions with objectives, and I was storing the objective data in a module script. So this can be compromised?
If that’s the case, where do I store this data? Or do I have to store everything in server scripts? Or server values (int/boolvalue) etc?
Yes, though I think it’s important to step back for a moment and address how exactly you’re using those ModuleScripts. Since the instance returned in a require does not cross the client/server boundary, an exploiter’s modifications to a ModuleScript’s environment would only apply to the client instance. If you intend to store objective data in a ModuleScript from a Script you’re fine.
If a ModuleScript exists in a container that replicates to the client, they can see it yes, but the client and server both receive different instances of a ModuleScript when it’s required. So with that in mind, if you’re requiring the ModuleScript with a Script and modifying it there then exploiters can neither see the server’s changes nor influence changes in the ModuleScript that the server would pick up.
You can continue to store data in ModuleScripts but just try not to make anything important hinge on the client. Like for example with your use case, the server can use ModuleScripts to track mission progress for players just fine. If you want the client to get any changed variables then you’d have to replicate it yourself via remotes.
Best practice for ModuleScripts that don’t have relevance to clients is to put them in server-only storages where the children don’t replicate, particularly ServerScriptService.
So I can require a ModuleScript that is inside ServerScriptService?
Like this is my module script right now.
--Mission1
local missionSettings = {}
missionSettings.Objective1 = 15
missionSettings.Objective2 = 10
return missionSettings
Right now I have this module script inside a PlayerGui (That is cloned from Replicated Storage)
So at the moment this data could be compromised then?
" If you intend to store objective data in a ModuleScript from a Script you’re fine."
This I’m a little fuzzy on what you mean here? what do you mean in a moudlescript from a script?
ModuleScripts can be required in any location so long as the script requiring the ModuleScript is in a container that will run the script (for example, LocalScripts are restricted in what containers they can execute in - if the Script or LocalScript can run, the require is legal).
Generally you should leave code out of PlayerGui and put it in PlayerScripts instead but in any case, from the way you currently have your script set up yes it could be compromised depending on how you have your objective system set up. If you intend to give players objectives or grant rewards for completion of them then you should be doing that from the server (Scripts).
If your current way of handling objectives is that a LocalScript updates these variables then yes it can be compromised as an exploiter could change these values to whatever they’d like. On the other hand, the server wouldn’t be able to see the object progress change if you update the values from a LocalScript and then expect a Script to be able to read and see the new values.
To expand a bit on the quoted bit you have up, it might be better to give you a more practical example and something easier to go off of to visualise what I mean here.
Here’s a chart I drew up explaining how changes in a ModuleScript are looked at in the engine:
(I use DevForum white theme so the background is white, sorry. You can open this in a new tab or the forum image viewer to inspect it in a larger size.)
Though back to what I meant by the quoted part and using the table to help us structure a more practical example: since an instance of a ModuleScript is shared only across the environment it’s required on (the server, client and command bar each receive a different copy of a required ModuleScript), pretty much what I said - keep using ModuleScripts! The threat of exploiters is very small, it’s mainly down to how you structure your code.
The way you set up your ModuleScript as-is is fine:
- A table is created.
- 15 is written to the Objective1 index.
- 10 is written to the Objective2 index.
- Return the aforementioned table when a script requires this.
Now suppose you require this from both a Script and a LocalScript: you have two tables. The LocalScript (or an exploiter, they’re equivalents) could:
Objectives.Objective1 = 999
And a Script could:
Objectives.Objective1 = 1
Any LocalScripts that require and print Objective1 will see 999 but a Script that does so will see 1. So while in this case an exploiter did indeed change one of the values of the table’s indices, the Script doesn’t see it. Therefore: you can keep storing mission progress in ModuleScripts as-is.
Hi! sorry for not reading all the long posts.
Yes moduleScripts can be manipulated locally only meaning, only the client doing it, will see the effect it has.
Even if the server has access to the same moduleScript, and uses some of the same functions in there, it will still work as intended, like there was no change at all.
If you store data in the modulescript that both client and server has access to, just make sure that the data is modified and checked on the server (like you would do with any other script)
Edit: I can see that February_Seventeenth has explained it pretty good for you!
I wrote a sample project if you’re interested in further seeing a practical example of what I’ve explained above. It’s a simple objective tracker where you have to click the spawn. I have a ModuleScript placed somewhere that can be seen by both the client and the server. The client simulates an exploited change by writing “foobar” to the progress table whenever it has to update the Gui. Some comments are left in the scripts for further help.
Objectives Sample Project.rbxl (40.3 KB)
Did the client compromise the ModuleScript and change variables? Yes, it added a new one. Does the server see it? Nope. So I guess the best way to wrap this up: keep using ModuleScripts! Just don’t track your progress with a LocalScript preferably.