Offensive Security Testing¶
DERSim can act as a controlled adversary: you arm one or more attacks and the simulator mutates the data it puts on the wire — SunSpec/Modbus, IEEE 2030.5 (CSIP), and OCPP — while its internal physics keep running truthfully. Use it to validate that your DERMS, CSMS, aggregator, or monitoring system detects compromised-device behavior, falsified telemetry, and machine-in-the-middle manipulation.
Attacks are armed and disarmed at runtime from the Offensive
Security Testing tab in the dashboard, or through the /offensive
REST API — per device, with no restart, and with a live truthful-vs-wire
diff.
!!! note "Replaces the old --compromised_behavior flag"
Earlier releases triggered a single fixed behavior with the
--compromised_behavior HACK_SCRIPT command-line option. That flag
has been removed. Everything it did is now available — alongside
many new attack types — through the Offensive Security Testing tab
and REST API. See Migrating from
--compromised_behavior.
Enabling offensive testing¶
Offensive testing is off by default and gated by a single launch flag:
--offensive_enable yes
When it is off, the offensive features are inactive, the REST endpoints return 404, and the dashboard tab is hidden. When it is on, a persistent OFFENSIVE TESTING ACTIVE banner appears in the dashboard whenever any attack is armed, and a Panic-disarm all button clears every device in one click. DoS-style attacks enforce their own non-bypassable rate ceilings.
Only data read by or published to external systems is mutated. Every other dashboard view (Overview, Battery, Grid Support, …) shows the device's truthful internal state. The SunSpec Client tab is the exception — it connects over Modbus on purpose, so it sees the falsified values exactly as a real client would.
The dashboard tab¶
The Offensive Security Testing tab has four panes:
| Pane | What it does |
|---|---|
| Catalog | Every available attack, grouped by family and filterable. Click Arm to add one to the selected device. Only attacks that apply to the device's enabled protocols are shown. |
| Armed | The attacks armed on the device — each with an enable/disable toggle, tunable parameters, condition gates, and Remove. |
| Wire Diff | The live truthful-vs-wire table: protocol, key, truthful value, mutated value, and the attack responsible. Refresh / Clear per device. |
| Banner | Device selector, the ACTIVE indicator, and Panic-disarm all. |
A typical loop: select a device → arm an attack → tune its parameters → watch the Wire Diff populate → disarm.
Attack categories¶
| Attack type | What it does | Examples |
|---|---|---|
| Falsified telemetry & identity | Read/emit-time value mutations on measurements, identity, nameplate ratings, and setpoints. Many are cross-protocol — one arm lands on SunSpec and CSIP (and identity also on OCPP). | falsify_device_identity, meas_low_v, meas_zero_p, nameplate_low_p, settings_high_p |
| OCPP payload manipulation | Malicious CP→CSMS message content. | boot_sql_injection, meter_negative_energy, falsified_disconnection |
| Protocol fuzzing | Walks outbound payload fields and applies one mutation per gated emit via a chosen strategy, bounded by a subtlety dial + rate ceiling. | fuzz_ocpp, fuzz_sunspec, fuzz_csip |
| Out-of-order / impossible state | State-machine and ordering violations. | double_authorize, stop_before_start, csip_inconsistent_state |
| Resource / denial-of-service | Rate-bounded flooding and oversized payloads. | ws_reconnect_storm, meter_value_flood, oversized_boot_fields |
| Physical-world fraud | Billing, capacity-market, and compliance falsification. | energy_theft, over_credit_soc, capacity_fraud, reactive_power_falsification |
DERSim is the charge-point / DER simulator, so every attack is something the device itself can produce. CSMS-side / DERMS-side attacks are out of scope — pair DERSim with a separate server-side tool for those.
SunSpec measurement & identity reference¶
The SunSpec telemetry & identity attacks cover the same falsifications
as the legacy --compromised_behavior options. Each applies
value = value × scaling + offset (or sets the value directly).
The voltage/frequency/current/apparent/reactive/power-factor and
zero/invert attacks also mutate the matching CSIP monitoring
scalar, so one arm falsifies both wires.
| Attack id | Effect | Mutation |
|---|---|---|
da_manipulation |
Modify the device ID | DA → 200 or 201 |
falsify_device_identity |
Change manufacturer & model | Prefix Evil to Mn/Md (SunSpec) and BootNotification vendor/model (OCPP) |
meas_p_always_nameplate |
Pin power to nameplate | W, VA = WMaxRtg, VAMaxRtg; Var = 0 |
meas_q_always_{minimum,maximum,zero} |
Pin reactive power | Var = −VarMaxAbsRtg / +VarMaxInjRtg / 0 |
meas_zero_p |
Zero power & current | W, VA, Var, A = 0 (SunSpec + CSIP) |
meas_invert_q |
Reverse reactive sign | Var ×= −1 (SunSpec + CSIP) |
meas_low_v / meas_high_v |
Falsify line voltage | V ×= 0.89 / 1.11 (SunSpec + CSIP) |
meas_low_l1_v / meas_high_l1_v |
Falsify L1 voltage | VL1 ×= 0.89 / 1.11 |
meas_low_f / meas_high_f |
Falsify frequency | Hz += −2.3 / +2.3 (SunSpec + CSIP) |
meas_low_amps / meas_high_amps |
Falsify current | A ×= 0.65 / 1.35 (SunSpec + CSIP) |
meas_high_s / meas_low_s |
Falsify apparent power | VA ×= 2.0 / 0.5 (SunSpec + CSIP) |
meas_high_q / meas_low_q |
Falsify reactive power | Var ×= 2.0 / 0.5 (SunSpec + CSIP) |
meas_low_pf / meas_low_reversed_pf |
Falsify power factor | PF shifted toward zero, clamped to [−1, 1] (SunSpec + CSIP) |
nameplate_* |
Scale published DER ratings | e.g. WMaxRtg, VAMaxRtg, VNomRtg × factor |
settings_* |
Scale setpoint limits | e.g. WMax, AMax, VNom × factor |
change_common_model_id / change_common_model_length |
Overwrite common-model registers | Mid / Len = constant |
The same SunSpec-side control is also reachable from the 64412 SunSpec Modbus model, so an attack can be armed over Modbus as well as from the dashboard:

Condition gates¶
Any armed attack can carry conditions — it only fires when all of its conditions are true on the current tick. With no conditions it fires on every emit.
| Condition | Fires when | Fields |
|---|---|---|
always |
every tick (default) | — |
soc_above / soc_below |
battery SOC crosses a threshold | threshold |
p_above / p_below |
active power crosses a threshold (W) | threshold_w |
every_n_ticks |
every Nth emit (flicker) | n |
after_n_ticks |
from the Nth emit onward (delayed onset) | n |
random_at_rate |
stochastically, per-tick probability | prob_per_tick, seed |
time_window |
inside an ISO start/end window | start_iso, end_iso |
For example, a voltage falsification gated by soc_above(threshold=90)
and every_n_ticks(n=3) only fires once the battery is nearly full, and
then only on every third emit.
Preset bundles¶
A bundle arms a named, one-click scenario built from several attacks. Loading a bundle replaces the device's armed set with the bundle's members.
| Bundle | Scenario |
|---|---|
stuck-at-nameplate |
DER misreports steady full-rated output (power at nameplate, reactive zero). |
low-v-storm |
Sustained under-voltage + under-frequency across SunSpec and CSIP. |
hostile-cp |
A compromised charge point end to end: injection, meter fraud, SoC lie, falsified disconnect, reconnect storm. |
compromised-csip-client |
A compromised 2030.5 client: inflated capacity, reactive-compliance falsification, contradictory DERStatus. |
grid-abnormal-trip-test |
Over-voltage + over-frequency excursion for IEEE 1547 ride-through / trip conformance. |
Arm one from the dashboard, or over REST:
POST /api/dersim/offensive/devices/<device_id>/presets/hostile-cp
Worked example: falsified identity¶
- Launch DERSim with
--offensive_enable yesand point a PV DER at your aggregator or monitoring system. - Arm
falsify_device_identityfrom the catalog (orPOST /api/dersim/offensive/devices/<id>/presets/falsify_device_identity). - The device now advertises
Evil <Manufacturer>/Evil <Model>on every wire it speaks — SunSpec common-model Mn/Md and, if OCPP is wired, the BootNotification vendor/model. The Wire Diff pane shows the deltas; your monitoring system should raise its device-identity detection. - Click Remove (or Panic-disarm all). The wire view returns to truthful immediately.
Migrating from --compromised_behavior¶
The --compromised_behavior command-line flag has been removed. The
replacement is strictly more capable:
| Then | Now |
|---|---|
| One global behavior, fixed at launch | Per-device attacks, armed/disarmed at runtime |
| SunSpec/Modbus only | SunSpec, OCPP, and CSIP — often the same attack on all three |
| No visibility | Live truthful-vs-wire diff + ACTIVE banner |
| Restart to change | Arm / tune / disarm with no restart |
If your lab scripts passed --compromised_behavior <script>, replace the
launch flag with a runtime POST …/presets/<id> call (single attack or
bundle) after the device registers. The only offensive-related launch
flag now is --offensive_enable yes.