diff --git a/virtweb_backend/Cargo.lock b/virtweb_backend/Cargo.lock
index 42bb251..83c763a 100644
--- a/virtweb_backend/Cargo.lock
+++ b/virtweb_backend/Cargo.lock
@@ -2159,18 +2159,6 @@ dependencies = [
  "serde_derive",
 ]
 
-[[package]]
-name = "serde-xml-rs"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782"
-dependencies = [
- "log",
- "serde",
- "thiserror",
- "xml-rs",
-]
-
 [[package]]
 name = "serde_derive"
 version = "1.0.193"
@@ -2677,7 +2665,6 @@ dependencies = [
  "reqwest",
  "rust-embed",
  "serde",
- "serde-xml-rs",
  "serde_json",
  "sysinfo",
  "tempfile",
@@ -2981,12 +2968,6 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "xml-rs"
-version = "0.8.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
-
 [[package]]
 name = "zerocopy"
 version = "0.7.31"
diff --git a/virtweb_backend/Cargo.toml b/virtweb_backend/Cargo.toml
index 75caaa4..a5e7125 100644
--- a/virtweb_backend/Cargo.toml
+++ b/virtweb_backend/Cargo.toml
@@ -22,7 +22,6 @@ actix-web-actors = "4.2.0"
 actix-http = "3.4.0"
 serde = { version = "1.0.193", features = ["derive"] }
 serde_json = "1.0.108"
-serde-xml-rs = "0.6.0"
 quick-xml = { version = "0.31.0", features = ["serialize", "overlapped-lists"] }
 futures-util = "0.3.28"
 anyhow = "1.0.75"
diff --git a/virtweb_backend/src/controllers/server_controller.rs b/virtweb_backend/src/controllers/server_controller.rs
index ba57a7a..ad413ec 100644
--- a/virtweb_backend/src/controllers/server_controller.rs
+++ b/virtweb_backend/src/controllers/server_controller.rs
@@ -16,7 +16,7 @@ struct StaticConfig {
     iso_mimetypes: &'static [&'static str],
     net_mac_prefix: &'static str,
     constraints: ServerConstraints,
-    builtin_network_rules: &'static [&'static str],
+    builtin_nwfilter_rules: &'static [&'static str],
 }
 
 #[derive(serde::Serialize)]
@@ -46,7 +46,7 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
         oidc_auth_enabled: !AppConfig::get().disable_oidc,
         iso_mimetypes: &constants::ALLOWED_ISO_MIME_TYPES,
         net_mac_prefix: constants::NET_MAC_ADDR_PREFIX,
-        builtin_network_rules: &constants::BUILTIN_NETWORK_FILTER_RULES,
+        builtin_nwfilter_rules: &constants::BUILTIN_NETWORK_FILTER_RULES,
         constraints: ServerConstraints {
             iso_max_size: constants::ISO_MAX_SIZE,
 
diff --git a/virtweb_frontend/src/App.tsx b/virtweb_frontend/src/App.tsx
index 00e7089..580545b 100644
--- a/virtweb_frontend/src/App.tsx
+++ b/virtweb_frontend/src/App.tsx
@@ -26,6 +26,7 @@ import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
 import { BaseLoginPage } from "./widgets/BaseLoginPage";
 import { ViewNetworkRoute } from "./routes/ViewNetworkRoute";
 import { HomeRoute } from "./routes/HomeRoute";
+import { NetworkFiltersListRoute } from "./routes/NetworkFiltersListRoute";
 
 interface AuthContext {
   signedIn: boolean;
@@ -61,6 +62,8 @@ export function App() {
           } />
           } />
 
+          } />
+
           } />
           } />
         
diff --git a/virtweb_frontend/src/api/NWFilterApi.ts b/virtweb_frontend/src/api/NWFilterApi.ts
index ae6fc4a..1cb9344 100644
--- a/virtweb_frontend/src/api/NWFilterApi.ts
+++ b/virtweb_frontend/src/api/NWFilterApi.ts
@@ -37,6 +37,10 @@ export interface NWFilter {
   rules: NWFilterRule[];
 }
 
+export function NWFilterURL(n: NWFilter, edit: boolean = false): string {
+  return `/nwfilter/${n.uuid}${edit ? "/edit" : ""}`;
+}
+
 export class NWFilterApi {
   /**
    * Get the entire list of networks
diff --git a/virtweb_frontend/src/api/NetworksApi.ts b/virtweb_frontend/src/api/NetworksApi.ts
index a7f6702..6c86c5d 100644
--- a/virtweb_frontend/src/api/NetworksApi.ts
+++ b/virtweb_frontend/src/api/NetworksApi.ts
@@ -39,10 +39,6 @@ export function NetworkURL(n: NetworkInfo, edit: boolean = false): string {
   return `/net/${n.uuid}${edit ? "/edit" : ""}`;
 }
 
-export function NetworkXMLURL(n: NetworkInfo): string {
-  return `/net/${n.uuid}/xml`;
-}
-
 export class NetworkApi {
   /**
    * Create a new network
diff --git a/virtweb_frontend/src/api/ServerApi.ts b/virtweb_frontend/src/api/ServerApi.ts
index 22a0016..71ea1f7 100644
--- a/virtweb_frontend/src/api/ServerApi.ts
+++ b/virtweb_frontend/src/api/ServerApi.ts
@@ -7,6 +7,7 @@ export interface ServerConfig {
   iso_mimetypes: string[];
   net_mac_prefix: string;
   constraints: ServerConstraints;
+  builtin_nwfilter_rules: string[];
 }
 
 export interface ServerConstraints {
diff --git a/virtweb_frontend/src/api/VMApi.ts b/virtweb_frontend/src/api/VMApi.ts
index 12564ef..9f58c46 100644
--- a/virtweb_frontend/src/api/VMApi.ts
+++ b/virtweb_frontend/src/api/VMApi.ts
@@ -133,10 +133,6 @@ export class VMInfo implements VMInfoInterface {
   get VNCURL(): string {
     return `/vm/${this.uuid}/vnc`;
   }
-
-  get XMLURL(): string {
-    return `/vm/${this.uuid}/xml`;
-  }
 }
 
 export class VMApi {
diff --git a/virtweb_frontend/src/routes/NetworkFiltersListRoute.tsx b/virtweb_frontend/src/routes/NetworkFiltersListRoute.tsx
new file mode 100644
index 0000000..a331857
--- /dev/null
+++ b/virtweb_frontend/src/routes/NetworkFiltersListRoute.tsx
@@ -0,0 +1,153 @@
+import VisibilityIcon from "@mui/icons-material/Visibility";
+import {
+  Button,
+  IconButton,
+  Paper,
+  Table,
+  TableBody,
+  TableCell,
+  TableContainer,
+  TableHead,
+  TableRow,
+  ToggleButton,
+  ToggleButtonGroup,
+  Typography,
+} from "@mui/material";
+import React from "react";
+import { useNavigate } from "react-router-dom";
+import { NWFilter, NWFilterApi, NWFilterURL } from "../api/NWFilterApi";
+import { AsyncWidget } from "../widgets/AsyncWidget";
+import { RouterLink } from "../widgets/RouterLink";
+import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
+import { ServerApi } from "../api/ServerApi";
+
+export function NetworkFiltersListRoute(): React.ReactElement {
+  const [list, setList] = React.useState();
+
+  const [count] = React.useState(1);
+
+  const load = async () => {
+    setList(await NWFilterApi.GetList());
+  };
+
+  return (
+     }
+    />
+  );
+}
+
+enum VisibleFilters {
+  All,
+  Builtin,
+  Custom,
+}
+
+function NetworkFiltersListRouteInner(p: {
+  list: NWFilter[];
+}): React.ReactElement {
+  const navigate = useNavigate();
+
+  const [visibleFilters, setVisibleFilters] = React.useState(
+    VisibleFilters.All
+  );
+
+  const filteredList = React.useMemo(() => {
+    if (visibleFilters === VisibleFilters.All) return p.list;
+
+    const onlyBuiltin = visibleFilters === VisibleFilters.Builtin;
+
+    return p.list.filter(
+      (f) =>
+        ServerApi.Config.builtin_nwfilter_rules.includes(f.name) === onlyBuiltin
+    );
+  }, [visibleFilters]);
+
+  return (
+    
+          
+           setVisibleFilters(v)}
+            aria-label="visible filters"
+          >
+            All
+            Builtin
+            Custom
+          
+          
+
+          
+            
+          
+        >
+      }
+    >
+      
+        
+          
+            
+              Name
+              Chain
+              Priority
+              Referenced filters
+              # of rules
+              Actions
+            
+          
+          
+            {filteredList.map((t) => {
+              return (
+                 navigate(NWFilterURL(t))}
+                >
+                  {t.name}
+                  
+                    {t.chain?.protocol ?? (
+                      
+                        None
+                      
+                    )}
+                  
+                  
+                    {t.priority ?? (
+                      
+                        None
+                      
+                    )}
+                  
+                  
+                    
+                      {t.join_filters.map((f, n) => (
+                        - {f}+                      ))}
+
+                  
+                  {t.rules.length}
+                  
+                    
+                      
+                        
+                      
+                    
+                  
+                
+              );
+            })}
+          
+
+      
+    
+  );
+}
diff --git a/virtweb_frontend/src/utils/DebugUtils.ts b/virtweb_frontend/src/utils/DebugUtils.ts
new file mode 100644
index 0000000..f6497d9
--- /dev/null
+++ b/virtweb_frontend/src/utils/DebugUtils.ts
@@ -0,0 +1,5 @@
+export function isDebug(): boolean {
+  return (
+    !import.meta.env.NODE_ENV || import.meta.env.NODE_ENV === "development"
+  );
+}
diff --git a/virtweb_frontend/src/widgets/BaseAuthenticatedPage.tsx b/virtweb_frontend/src/widgets/BaseAuthenticatedPage.tsx
index 4a91996..9664591 100644
--- a/virtweb_frontend/src/widgets/BaseAuthenticatedPage.tsx
+++ b/virtweb_frontend/src/widgets/BaseAuthenticatedPage.tsx
@@ -3,7 +3,9 @@ import {
   mdiDisc,
   mdiHome,
   mdiInformation,
-  mdiLan
+  mdiLan,
+  mdiSecurity,
+  mdiSecurityNetwork,
 } from "@mdi/js";
 import Icon from "@mdi/react";
 import {
@@ -17,6 +19,7 @@ import {
 import { Outlet, useLocation } from "react-router-dom";
 import { RouterLink } from "./RouterLink";
 import { VirtWebAppBar } from "./VirtWebAppBar";
+import { isDebug } from "../utils/DebugUtils";
 
 export function BaseAuthenticatedPage(): React.ReactElement {
   return (
@@ -60,6 +63,14 @@ export function BaseAuthenticatedPage(): React.ReactElement {
             uri="/net"
             icon={}
           />
+          {/* TODO : remove debug marker */}
+          {isDebug() && (
+            }
+            />
+          )}