diff --git a/google/README.md b/google/README.md
index f9493cf98..34b54001f 100644
--- a/google/README.md
+++ b/google/README.md
@@ -28,7 +28,7 @@ This directory contains all Tsunami plugins published by Google.
* [Exposed Kubernetes APIDetector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/kubernetes)
* [Exposed PHPUnit Vulnerable eval-stdin.php Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/phpunit)
* [Exposed Spring Boot Actuator Endpoint Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/spring)
-* [Exposed WordPress Installation Page Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/wordpress)
+* [Exposed WordPress Installation Page Detector, now updated to Templated format](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/exposedui/Wordpress_UnfinishedInstall_ExposedUI.textproto)
#### Remote Code Execution (RCE)
* [PHP RCE (CVE-2012-1823) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/rce/cve20121823)
diff --git a/google/detectors/exposedui/wordpress/README.md b/google/detectors/exposedui/wordpress/README.md
deleted file mode 100644
index e4fd5a139..000000000
--- a/google/detectors/exposedui/wordpress/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# WordPress Exposed Installation Page Detector
-
-This detector checks whether a WordPress install is unfinished. An unfinished
-WordPress installation exposes the /wp-admin/install.php page, which allows
-attacker to set the admin password and possibly compromise the system.
-
-## Build jar file for this plugin
-
-Using `gradlew`:
-
-```shell
-./gradlew jar
-```
-
-Tsunami identifiable jar file is located at `build/libs` directory.
diff --git a/google/detectors/exposedui/wordpress/build.gradle b/google/detectors/exposedui/wordpress/build.gradle
deleted file mode 100644
index a25809032..000000000
--- a/google/detectors/exposedui/wordpress/build.gradle
+++ /dev/null
@@ -1,48 +0,0 @@
-plugins {
- id 'java-library'
-}
-
-description = 'Tsunami VulnDetector plugin for exposed WordPress installation page.'
-group = 'com.google.tsunami'
-version = '0.0.1-SNAPSHOT'
-
-repositories {
- maven { // The google mirror is less flaky than mavenCentral()
- url 'https://maven-central.storage-download.googleapis.com/repos/central/data/'
- }
- mavenCentral()
- mavenLocal()
-}
-
-
-
-def coreRepoBranch = System.getenv("GITBRANCH_TSUNAMI_CORE") ?: "stable"
-def tcsRepoBranch = System.getenv("GITBRANCH_TSUNAMI_TCS") ?: "stable"
-
-dependencies {
- implementation "com.google.flogger:flogger:0.9"
- implementation "com.google.flogger:google-extensions:0.9"
- implementation "com.google.flogger:flogger-system-backend:0.9"
- implementation "com.google.guava:guava:33.0.0-jre"
- implementation "com.google.protobuf:protobuf-java:3.25.5"
- implementation "com.google.protobuf:protobuf-javalite:3.25.5"
- implementation "com.google.protobuf:protobuf-java-util:3.25.5"
- implementation("com.google.tsunami:tsunami-common") {
- version { branch = "${coreRepoBranch}" }
- }
- implementation("com.google.tsunami:tsunami-plugin") {
- version { branch = "${coreRepoBranch}" }
- }
- implementation("com.google.tsunami:tsunami-proto") {
- version { branch = "${coreRepoBranch}" }
- }
- implementation "javax.inject:javax.inject:1"
- implementation "org.jsoup:jsoup:1.9.2"
-
- testImplementation "com.google.truth:truth:1.4.4"
- testImplementation "com.google.truth.extensions:truth-java8-extension:1.4.4"
- testImplementation "com.google.truth.extensions:truth-proto-extension:1.4.4"
- testImplementation "com.squareup.okhttp3:mockwebserver:3.12.0"
- testImplementation "junit:junit:4.13.2"
- testImplementation "org.mockito:mockito-core:5.18.0"
-}
diff --git a/google/detectors/exposedui/wordpress/settings.gradle b/google/detectors/exposedui/wordpress/settings.gradle
deleted file mode 100644
index a682e1e0e..000000000
--- a/google/detectors/exposedui/wordpress/settings.gradle
+++ /dev/null
@@ -1,12 +0,0 @@
-rootProject.name = 'wordpress_exposed_installation_page'
-
-def coreRepository = System.getenv("GITREPO_TSUNAMI_CORE") ?: "https://github.com/google/tsunami-security-scanner.git"
-def tcsRepository = System.getenv("GITREPO_TSUNAMI_TCS") ?: "https://github.com/google/tsunami-security-scanner-callback-server.git"
-
-sourceControl {
- gitRepository("${coreRepository}") {
- producesModule("com.google.tsunami:tsunami-common")
- producesModule("com.google.tsunami:tsunami-plugin")
- producesModule("com.google.tsunami:tsunami-proto")
- }
-}
diff --git a/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetector.java b/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetector.java
deleted file mode 100644
index ff0f0eace..000000000
--- a/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetector.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.tsunami.plugins.detectors.exposedui.wordpress;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.ImmutableList.toImmutableList;
-import static com.google.tsunami.common.net.http.HttpRequest.get;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.flogger.GoogleLogger;
-import com.google.protobuf.util.Timestamps;
-import com.google.tsunami.common.data.NetworkServiceUtils;
-import com.google.tsunami.common.net.http.HttpClient;
-import com.google.tsunami.common.net.http.HttpResponse;
-import com.google.tsunami.common.time.UtcClock;
-import com.google.tsunami.plugin.PluginType;
-import com.google.tsunami.plugin.VulnDetector;
-import com.google.tsunami.plugin.annotations.ForWebService;
-import com.google.tsunami.plugin.annotations.PluginInfo;
-import com.google.tsunami.proto.DetectionReport;
-import com.google.tsunami.proto.DetectionReportList;
-import com.google.tsunami.proto.DetectionStatus;
-import com.google.tsunami.proto.NetworkService;
-import com.google.tsunami.proto.Severity;
-import com.google.tsunami.proto.TargetInfo;
-import com.google.tsunami.proto.Vulnerability;
-import com.google.tsunami.proto.VulnerabilityId;
-import java.io.IOException;
-import java.time.Clock;
-import java.time.Instant;
-import javax.inject.Inject;
-import org.jsoup.Jsoup;
-import org.jsoup.select.Elements;
-
-/** A {@link VulnDetector} that detects unfinished WordPress install. */
-@PluginInfo(
- type = PluginType.VULN_DETECTION,
- name = "WordPressInstallPageDetector",
- version = "0.1",
- description =
- "This detector checks whether a WordPress install is unfinished. An unfinished WordPress"
- + " installation exposes the /wp-admin/install.php page, which allows attacker to set"
- + " the admin password and possibly compromise the system.",
- author = "Tsunami Team (tsunami-dev@google.com)",
- bootstrapModule = WordPressInstallPageDetectorBootstrapModule.class)
-@ForWebService
-public final class WordPressInstallPageDetector implements VulnDetector {
- private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
-
- @VisibleForTesting
- static final String FINDING_RECOMMENDATION_TEXT =
- "Do not leave this installation page in place. Either finish the installation or remove"
- + " Wordpress.";
-
- private final Clock utcClock;
- private final HttpClient httpClient;
-
- @Inject
- WordPressInstallPageDetector(@UtcClock Clock utcClock, HttpClient httpClient) {
- this.utcClock = checkNotNull(utcClock);
- this.httpClient = checkNotNull(httpClient);
- }
-
- @Override
- public ImmutableList getAdvisories() {
- return ImmutableList.of(
- Vulnerability.newBuilder()
- .setMainId(
- VulnerabilityId.newBuilder()
- .setPublisher("GOOGLE")
- .setValue("UNFINISHED_WORD_PRESS_INSTALLATION"))
- .setSeverity(Severity.CRITICAL)
- .setTitle("Unfinished WordPress Installation")
- // TODO(b/147455416): determine CVSS score.
- .setDescription(
- "An unfinished WordPress installation exposes the /wp-admin/install.php page, which"
- + " allows attacker to set the admin password and possibly compromise the"
- + " system.")
- .setRecommendation(FINDING_RECOMMENDATION_TEXT)
- .build());
- }
-
- @Override
- public DetectionReportList detect(
- TargetInfo targetInfo, ImmutableList matchedServices) {
- logger.atInfo().log("Starting unfinished install page detection for WordPress.");
- DetectionReportList detectionReports =
- DetectionReportList.newBuilder()
- .addAllDetectionReports(
- matchedServices.stream()
- // TODO(b/147455416): checking web service is not needed once we enable
- // service name filtering on this plugin.
- .filter(NetworkServiceUtils::isWebService)
- .filter(this::isServiceVulnerable)
- .map(networkService -> buildDetectionReport(targetInfo, networkService))
- .collect(toImmutableList()))
- .build();
-
- logger.atInfo().log(
- "WordPressInstallPageDetector finished, detected '%d' vulns.",
- detectionReports.getDetectionReportsCount());
- return detectionReports;
- }
-
- private boolean isServiceVulnerable(NetworkService networkService) {
- String targetUri =
- NetworkServiceUtils.buildWebApplicationRootUrl(networkService)
- + "wp-admin/install.php?step=1";
- try {
- // This is a blocking call.
- HttpResponse response =
- httpClient.send(get(targetUri).withEmptyHeaders().build(), networkService);
- return response.status().isSuccess()
- // TODO(b/147455416): checking WordPress string is not needed once we have plugin
- // matching logic.
- && response
- .bodyString()
- .map(body -> body.contains("WordPress") && responseHasSetupForm(body))
- .orElse(false);
- } catch (IOException e) {
- logger.atWarning().withCause(e).log("Unable to query '%s'.", targetUri);
- return false;
- }
- }
-
- private static boolean responseHasSetupForm(String responseBody) {
- Elements installationForm = Jsoup.parse(responseBody).select("form#setup");
- if (installationForm.isEmpty()) {
- logger.atInfo().log("WordPress has already been installed.");
- return false;
- } else {
- logger.atInfo().log("Found unfinished WordPress installation!");
- return true;
- }
- }
-
- private DetectionReport buildDetectionReport(
- TargetInfo scannedTarget, NetworkService vulnerableNetworkService) {
- return DetectionReport.newBuilder()
- .setTargetInfo(scannedTarget)
- .setNetworkService(vulnerableNetworkService)
- .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(utcClock).toEpochMilli()))
- .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED)
- .setVulnerability(this.getAdvisories().get(0))
- .build();
- }
-}
diff --git a/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorBootstrapModule.java b/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorBootstrapModule.java
deleted file mode 100644
index 3903ec60f..000000000
--- a/google/detectors/exposedui/wordpress/src/main/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorBootstrapModule.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.tsunami.plugins.detectors.exposedui.wordpress;
-
-import com.google.tsunami.plugin.PluginBootstrapModule;
-
-/** A {@link PluginBootstrapModule} for {@link WordPressInstallPageDetector}. */
-public final class WordPressInstallPageDetectorBootstrapModule extends PluginBootstrapModule {
-
- @Override
- protected void configurePlugin() {
- registerPlugin(WordPressInstallPageDetector.class);
- }
-}
diff --git a/google/detectors/exposedui/wordpress/src/test/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorTest.java b/google/detectors/exposedui/wordpress/src/test/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorTest.java
deleted file mode 100644
index 7e758d7a3..000000000
--- a/google/detectors/exposedui/wordpress/src/test/java/com/google/tsunami/plugins/detectors/exposedui/wordpress/WordPressInstallPageDetectorTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.tsunami.plugins.detectors.exposedui.wordpress;
-
-import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
-import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostname;
-import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Resources;
-import com.google.inject.Guice;
-import com.google.protobuf.util.Timestamps;
-import com.google.tsunami.common.net.http.HttpClientModule;
-import com.google.tsunami.common.net.http.HttpStatus;
-import com.google.tsunami.common.time.testing.FakeUtcClock;
-import com.google.tsunami.common.time.testing.FakeUtcClockModule;
-import com.google.tsunami.proto.DetectionReport;
-import com.google.tsunami.proto.DetectionStatus;
-import com.google.tsunami.proto.NetworkEndpoint;
-import com.google.tsunami.proto.NetworkService;
-import com.google.tsunami.proto.ServiceContext;
-import com.google.tsunami.proto.Software;
-import com.google.tsunami.proto.TargetInfo;
-import com.google.tsunami.proto.TransportProtocol;
-import com.google.tsunami.proto.WebServiceContext;
-import java.io.IOException;
-import java.time.Instant;
-import javax.inject.Inject;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link WordPressInstallPageDetector}. */
-@RunWith(JUnit4.class)
-public final class WordPressInstallPageDetectorTest {
-
- private final FakeUtcClock fakeUtcClock =
- FakeUtcClock.create().setNow(Instant.parse("2020-01-01T00:00:00.00Z"));
-
- private MockWebServer mockWebServer;
-
- @Inject private WordPressInstallPageDetector detector;
-
- @Before
- public void setUp() {
- mockWebServer = new MockWebServer();
-
- Guice.createInjector(
- new FakeUtcClockModule(fakeUtcClock),
- new HttpClientModule.Builder().build(),
- new WordPressInstallPageDetectorBootstrapModule())
- .injectMembers(this);
- }
-
- @After
- public void tearDown() throws IOException {
- mockWebServer.shutdown();
- }
-
- @Test
- public void detect_whenResponseIsSetupForm_reportsVuln() throws IOException {
- startMockWebServer(
- "/wp-admin/install.php",
- HttpStatus.OK.code(),
- Resources.toString(
- Resources.getResource(this.getClass(), "testdata/enUsInstallPage.html"), UTF_8));
- ImmutableList httpServices =
- ImmutableList.of(
- NetworkService.newBuilder()
- .setNetworkEndpoint(
- forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
- .setTransportProtocol(TransportProtocol.TCP)
- .setSoftware(Software.newBuilder().setName("WordPress"))
- .setServiceName("http")
- .build());
-
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices)
- .getDetectionReportsList())
- .containsExactly(
- DetectionReport.newBuilder()
- .setTargetInfo(buildTargetInfo(forHostname(mockWebServer.getHostName())))
- .setNetworkService(httpServices.get(0))
- .setDetectionTimestamp(Timestamps.fromMillis(fakeUtcClock.millis()))
- .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED)
- .setVulnerability(detector.getAdvisories().get(0))
- .build());
- }
-
- @Test
- public void detect_whenResponseIsLocalizedSetupForm_reportsVuln() throws IOException {
- startMockWebServer(
- "/wp-admin/install.php",
- HttpStatus.OK.code(),
- Resources.toString(
- Resources.getResource(this.getClass(), "testdata/zhCnInstallPage.html"), UTF_8));
- ImmutableList httpServices =
- ImmutableList.of(
- NetworkService.newBuilder()
- .setNetworkEndpoint(
- forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
- .setTransportProtocol(TransportProtocol.TCP)
- .setSoftware(Software.newBuilder().setName("WordPress"))
- .setServiceName("http")
- .build());
-
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices)
- .getDetectionReportsList())
- .containsExactly(
- DetectionReport.newBuilder()
- .setTargetInfo(buildTargetInfo(forHostname(mockWebServer.getHostName())))
- .setNetworkService(httpServices.get(0))
- .setDetectionTimestamp(Timestamps.fromMillis(fakeUtcClock.millis()))
- .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED)
- .setVulnerability(detector.getAdvisories().get(0))
- .build());
- }
-
- @Test
- public void detect_whenNonEmptyAppRoot_reportsVuln() throws IOException {
- startMockWebServer(
- "/wordpress/wp-admin/install.php",
- HttpStatus.OK.code(),
- Resources.toString(
- Resources.getResource(this.getClass(), "testdata/enUsInstallPage.html"), UTF_8));
- ImmutableList httpServices =
- ImmutableList.of(
- NetworkService.newBuilder()
- .setNetworkEndpoint(
- forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
- .setTransportProtocol(TransportProtocol.TCP)
- .setSoftware(Software.newBuilder().setName("WordPress"))
- .setServiceName("http")
- .setServiceContext(
- ServiceContext.newBuilder()
- .setWebServiceContext(
- WebServiceContext.newBuilder().setApplicationRoot("/wordpress")))
- .build());
-
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices)
- .getDetectionReportsList())
- .containsExactly(
- DetectionReport.newBuilder()
- .setTargetInfo(buildTargetInfo(forHostname(mockWebServer.getHostName())))
- .setNetworkService(httpServices.get(0))
- .setDetectionTimestamp(Timestamps.fromMillis(fakeUtcClock.millis()))
- .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED)
- .setVulnerability(detector.getAdvisories().get(0))
- .build());
- }
-
- @Test
- public void detect_whenWordPressAlreadyInstalled_doesNotReportVuln() throws IOException {
- startMockWebServer(
- "/wp-admin/install.php",
- HttpStatus.OK.code(),
- Resources.toString(
- Resources.getResource(this.getClass(), "testdata/alreadyInstalledPage.html"), UTF_8));
- ImmutableList httpServices =
- ImmutableList.of(
- NetworkService.newBuilder()
- .setNetworkEndpoint(
- forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
- .setTransportProtocol(TransportProtocol.TCP)
- .setSoftware(Software.newBuilder().setName("WordPress"))
- .setServiceName("http")
- .build());
-
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices)
- .getDetectionReportsList())
- .isEmpty();
- }
-
- @Test
- public void detect_whenNonWordPressWebApp_ignoresServices() throws IOException {
- startMockWebServer("/wp-admin/install.php", HttpStatus.NOT_FOUND.code(), "");
- ImmutableList httpServices =
- ImmutableList.of(
- NetworkService.newBuilder()
- .setNetworkEndpoint(
- forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
- .setTransportProtocol(TransportProtocol.TCP)
- .setSoftware(Software.newBuilder().setName("Jenkins"))
- .setServiceName("http")
- .build());
-
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices)
- .getDetectionReportsList())
- .isEmpty();
- }
-
- @Test
- public void detect_whenNonHttpNetworkService_ignoresServices() {
- ImmutableList nonHttpServices =
- ImmutableList.of(
- NetworkService.newBuilder().setServiceName("ssh").build(),
- NetworkService.newBuilder().setServiceName("rdp").build());
- assertThat(
- detector
- .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), nonHttpServices)
- .getDetectionReportsList())
- .isEmpty();
- }
-
- @Test
- public void detect_whenEmptyNetworkService_generatesEmptyDetectionReports() {
- assertThat(
- detector
- .detect(
- buildTargetInfo(forHostname(mockWebServer.getHostName())), ImmutableList.of())
- .getDetectionReportsList())
- .isEmpty();
- }
-
- private void startMockWebServer(String url, int responseCode, String response)
- throws IOException {
- mockWebServer.enqueue(new MockResponse().setResponseCode(responseCode).setBody(response));
- mockWebServer.start();
- mockWebServer.url(url);
- }
-
- private static TargetInfo buildTargetInfo(NetworkEndpoint networkEndpoint) {
- return TargetInfo.newBuilder().addNetworkEndpoints(networkEndpoint).build();
- }
-}
diff --git a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/alreadyInstalledPage.html b/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/alreadyInstalledPage.html
deleted file mode 100644
index f38894e7d..000000000
--- a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/alreadyInstalledPage.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
- WordPress › Installation
-
-
-
-
-
-
-
- WordPress
-
- Already Installed
- You appear to have already installed WordPress. To reinstall please clear your old database tables first.
-
- Log In
-
-
-
diff --git a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/enUsInstallPage.html b/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/enUsInstallPage.html
deleted file mode 100644
index 843c46934..000000000
--- a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/enUsInstallPage.html
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
- WordPress › Installation
-
-
-
-
-
-
-
- WordPress
-
- Welcome
- Welcome to the famous five-minute WordPress installation process! Just fill in the information below and you’ll be on your way to using the most extendable and powerful personal publishing platform in the world.
-
- Information needed
- Please provide the following information. Don’t worry, you can always change these settings later.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/zhCnInstallPage.html b/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/zhCnInstallPage.html
deleted file mode 100644
index 7cda4420b..000000000
--- a/google/detectors/exposedui/wordpress/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/wordpress/testdata/zhCnInstallPage.html
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
- WordPress › 安装
-
-
-
-
-
-
-
- WordPress
-
- 欢迎
- 欢迎使用著名的WordPress五分钟安装程序!请简单地填写下面的表格,来开始使用这个世界上最具扩展性、最强大的个人信息发布平台。
-
- 需要信息
- 您需要填写一些基本信息。无需担心填错,这些信息以后可以再次修改。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/templated/templateddetector/plugins/exposedui/Wordpress_UnfinishedInstall_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/Wordpress_UnfinishedInstall_ExposedUI.textproto
new file mode 100644
index 000000000..f9e62aafd
--- /dev/null
+++ b/templated/templateddetector/plugins/exposedui/Wordpress_UnfinishedInstall_ExposedUI.textproto
@@ -0,0 +1,60 @@
+# proto-file: proto/templated_plugin.proto
+# proto-message: TemplatedPlugin
+
+###############
+# PLUGIN INFO #
+###############
+
+info: {
+ type: VULN_DETECTION
+ name: "Wordpress_UnfinishedInstall_ExposedUI"
+ author:
+ "Robert Dick (robert@doyensec.com) for templated version, "
+ "Tsunami Team (tsunami-dev@google.com) for original Java version"
+ version: "1.0"
+}
+
+finding: {
+ main_id: {
+ publisher: "GOOGLE"
+ value: "UNFINISHED_WORD_PRESS_INSTALLATION"
+ }
+ severity: CRITICAL
+ title: "Unfinished WordPress Installation"
+ description:
+ "An unfinished WordPress installation exposes the /wp-admin/install.php page,"
+ " which allows attacker to set the admin password and possibly compromise the system."
+ recommendation: "Do not leave this installation page in place. Either finish the installation or remove Wordpress."
+}
+
+
+###########
+# ACTIONS #
+###########
+
+actions: {
+ name: "fingerprint_wordpress_install"
+ http_request: {
+ method: GET
+ uri: "/wp-admin/install.php?step=1"
+ response: {
+ http_status: 200
+ expect_all: {
+ conditions: [
+ { body: {} contains: 'WordPress' },
+ { body: {} contains: '
\n\n