skip to content

In OWASP ZAP, which component provides the local proxy listener a browser points at, and what stays in core?

level: middleimportance: should knowfreq 42%

answer

  1. not core — an add-on binds the socket
  2. the network add-on owns the listener
  3. core's proxy packages are deprecated shims
  4. LocalServer, plus -host and -port

basics

~20 s

The network add-on provides it. Its LocalServer class binds the configured address and port, and ExtensionNetwork registers the -host and -port arguments. Core keeps deprecated proxy classes plus four live listener interfaces so older add-ons still compile.

solid answer

~40 s

The live local proxy is the `network` add-on's. `LocalServer` binds the configured address and port, and `ExtensionNetwork` is what registers the `-host` and `-port` command-line arguments. Core still ships `org.parosproxy.paros.core.proxy` and `org.zaproxy.zap.extension.proxies`, but nearly everything in them carries `@Deprecated` — core's own `CommandLine.PORT` and `CommandLine.HOST` constants are deprecated too, with the note that they are no longer used. What stays live in core is a handful of listener interfaces — `ProxyListener`, `ConnectRequestProxyListener`, `OverrideMessageProxyListener`, `ArrangeableProxyListener` — so add-ons written against the old proxy still compile, plus a `ProxyParam` that the add-on writes the real address and port back into. So grepping core for proxy classes finds them and tells you nothing about what is listening; the live registration is the add-on's.

go deeper

for a junior

Remember the headline: the proxy your browser talks to comes from the network add-on, not from ZAP core. The -host and -port flags come from that same add-on, which is why they are not core's own options.

for a middle

Explain the shim. Core kept deprecated proxy classes plus four live listener interfaces so old add-ons compile, while LocalServer in the network add-on binds the socket and ExtensionNetwork registers the flags.

for a senior

Show how you would settle an ownership question in practice: check what registers the behaviour at runtime rather than what contains the string, and treat a deprecated class as evidence of a shim only.

for a principal

The transferable point is that a subsystem can move out and leave a compiling, findable, still-updated shim behind. Decide how your team states ownership in docs and reviews so nobody argues from a grep result.

## What is actually listening When you point a browser at ZAP, the socket accepting that connection is opened by the **`network` add-on**, not by the core program. The add-on's `LocalServer` class binds an address and a port taken from a `LocalServerConfig`, and `ExtensionNetwork` starts it. The same add-on registers the `-host` and `-port` command-line arguments through the ordinary extension hook that any add-on uses to add a flag, and it also owns the locally generated root certificate authority and the `-certload`, `-certpubdump` and `-certfulldump` options that go with it. That matters because almost everything a newcomer calls "the ZAP proxy" is add-on code: the listener, the two arguments that place it, and the certificate authority it signs with are one component's surface, and core's contribution is the interfaces around them. When the main listener cannot bind in a headless run, the add-on does not carry on quietly: it logs the failure and terminates the process. ## What core still contains Core did not delete the old proxy when the subsystem moved out. It left two packages behind: - `org.parosproxy.paros.core.proxy` — the original Paros-era proxy, now mostly `@Deprecated`; - `org.zaproxy.zap.extension.proxies` — the later "additional proxies" extension, `@Deprecated` throughout. What is still **live** in the first package is a small set of listener interfaces: `ProxyListener`, `ConnectRequestProxyListener`, `OverrideMessageProxyListener` and `ArrangeableProxyListener`. They are kept so that add-ons written against the old proxy still compile and still get called; the add-on runs a legacy handler that drives them. The classes that used to *do* the proxying — `ProxyServer`, `ProxyThread`, `ProxyParam` — are deprecated shims. | what you are looking for | where it actually lives | what core still holds | |---|---|---| | the listening socket | the `network` add-on's `LocalServer` | `ProxyServer` / `ProxyThread`, deprecated | | the `-host` and `-port` flags | `ExtensionNetwork`'s command-line arguments | `CommandLine.HOST` / `CommandLine.PORT`, deprecated | | the address and port as stored state | the add-on's `LocalServerConfig` | `ProxyParam`, deprecated but still written to | | the callback an add-on implements | — | `ProxyListener` and three siblings, **live** | ## Why a grep of core gets this wrong This is the single most common mistake on this subject, and it is not carelessness. Every identifier involved is real. Search core for `ProxyServer` and you find a class. Search core for `-port` and you find a constant. Nothing in the result tells you that the class is never instantiated by the running program and that the constant is annotated as no longer used. The rule that closes the gap is: 1. **A hit on a deprecated class is evidence the shim exists, not that the capability does.** Read the annotation before you read the code. 2. **A hit in a changelog, a help page or a comment is documentation of a removal, not a live capability.** 3. **Ask which component registers the behaviour at runtime**, rather than which file contains the string. Core's built-in extension list is explicit and short, and no proxy extension appears in it. ## The add-on feeds the core shim There is a detail that makes the trap worse and is worth knowing for its own sake. When the add-on starts its main listener it calls back into core's deprecated `ProxyParam` and writes the real address and port into it. So the deprecated object is not stale — it is a mirror, kept current by the add-on, so that older code reading core's proxy settings sees the truth. A reader who finds `ProxyParam` holding the correct port can reasonably conclude that core owns the proxy. It does not; it owns a copy of two of its fields. ## What this means when you run ZAP in a pipeline Three practical consequences for someone driving ZAP from CI: - **The listener, the flags and the root authority arrive together.** They are one add-on's surface, so anything you conclude about one of them is a conclusion about that same component. - **`-host` and `-port` are add-on arguments**, so they are parsed only once that add-on is loaded. An unrecognised-argument failure and a missing-add-on failure are the same failure wearing different clothes. - **Say which half you mean when you describe it.** "ZAP's proxy" is ambiguous; "the `network` add-on's local server" is not, and the distinction is exactly the one that decides whether a given class in the source tree is doing anything. The general lesson beneath the specifics: in this program a subsystem can move out of core and leave a shim behind, and the shim keeps compiling, keeps being findable, and can even keep being updated. Ownership is a runtime fact about registration, and only registration settles it.

  • If core's proxy classes are deprecated, why does core still expose ProxyListener?
    So that add-ons written against the old proxy keep compiling and keep receiving messages. Four listener interfaces stayed live in core and the `network` add-on drives them through a legacy handler, which is why the contract survived even though the implementation left.
  • Why does the network add-on write the address and port back into core's deprecated ProxyParam?
    So that older code which still reads core's proxy settings sees the real values. It makes the shim a maintained mirror rather than dead state — and it is why finding a correct port in `ProxyParam` is not evidence that core owns the listener.

saying these in an interview costs you the question

  • Says the proxy is in core because core contains proxy classes
  • Treats core's ProxyServer as the class that opens the listener
  • Believes -port is one of core's own command-line options
  • Thinks core's dynssl package still manages the root certificate
  • Argues ownership from a grep hit instead of from what registers it