Do not open a public issue. Use GitHub's private vulnerability reporting on this repository (Security → Report a vulnerability), or contact the repository owner, @malgaroshy-maker, privately via GitHub.
One maintainer, working alone: expect an acknowledgement rather than a same-day fix. If you do not hear anything within two weeks, ping the same channel again before going public.
There is no server, no account system and no hosted component. The attack surface is entirely local listeners and the files the app reads:
- the tag bus WebSocket server in the engine
- the Python sidecar and its protocol drivers
- the Modbus TCP server the Modbus driver stands up
- the OPC UA server the
opcua-serverdriver stands up - scene files, which are JSON the editor parses and will happily be shared between students
Out of scope: the third-party PLC or SCADA package on the other end of a driver, and Godot and .NET themselves.
This is a teaching tool. Everything it listens on is meant to be reachable only from the machine running it, and mostly is.
| Listener | Binds | State |
|---|---|---|
| Tag bus (engine) | 127.0.0.1:7411 |
Loopback, deliberately. engine/src/TagBus/TagBusServer.cs |
| OPC UA server driver | opc.tcp://127.0.0.1:4841/ |
Loopback, deliberately. drivers/opcua_server.py |
| Modbus TCP driver | 0.0.0.0:502 |
A bug, being fixed — see below |
ModbusTcpServer itself defaults to 127.0.0.1. The driver overrides that
with 0.0.0.0 (sidecar/factoryforge_sidecar/drivers/modbus_tcp.py), and the
driver's default is the one that ships. So a user who picks the Modbus driver and
connects gets a writable simulator with no authentication, reachable by anyone
on the same subnet — which on a classroom or lab network is a real network,
not a hypothetical one.
Two things make it narrower than it sounds, and neither of them makes it acceptable:
- Nothing listens until a user chooses Modbus and presses Apply & Connect. The
driver dialog defaults to
plcsim-advanced(engine/src/Editor/DriverConnectionUI.cs), and until then no sidecar is running at all. - There is nothing of value behind it. Writing to it moves boxes in a simulated factory.
The fix is HP-22 in the hardening plan: default to
127.0.0.1, make binding wider an explicit choice, and harden the hand-written
server while we are in there — length-validate frames, put a deadline on reads,
cap connections, and have stop() close established clients rather than only the
listener.
Until that lands, if you use the Modbus driver on a network you do not
control, pass an explicit host: -o host 127.0.0.1.
opcua_server.py selects NoSecurity unconditionally — anonymous and
unencrypted. That is defensible for a loopback endpoint and it is what the code
comment says, but the same comment implies certificates "can be configured", and
they cannot: nothing reads a certificate option. Either making it true or
removing the implication is HP-29.
All of these are open items in docs/HARDENING_PLAN.md
rather than secrets:
- A scene file is parsed without validation and destroys the open scene first.
LoadSceneFromFileclears the current scene before it has read, parsed or validated the new one, and malformed JSON throws rather than being rejected. Opening a scene somebody sent you can lose the scene you had. HP-02, HP-07. - Non-finite analog values.
NaNand infinity can be forced through the UI and coerced into a float tag, and can be decoded out of Modbus registers into a JSON payload the C# parser then rejects. HP-23. - Modbus frames are not length-validated. An empty PDU indexes off the end;
reads have no deadline, so a half-open client withholding bytes pins a
coroutine;
stop()leaves established sessions open. HP-22.
- Releases are not code-signed, so Windows SmartScreen warns on first run.
That is a deliberate, documented choice, not a compromise — see
docs/PACKAGING.md. (There are also no published releases yet, so there is currently nothing to warn about.) - Forced tags override the PLC. That is the feature. A forced tag is a value deliberately disagreeing with the simulation, which is how you test what your program does with a stuck sensor.
- The driver writes to a PLC you point it at. That is also the feature. Point
it at a controller you own;
AGENTS.mdrecords what happened the one time a driver took more ownership of a CPU than it should have.
There are no releases yet, so there is no version to support. master is the
only thing that exists. When the first tag lands (HP-09), this section gets a
real answer.