diff --git a/contrib/xml2/expected/xml2.out b/contrib/xml2/expected/xml2.out
index 3bf676fb400717c12f8f550108f048568feb28f7..eba6ae60364988ce633db5a1137666f28e270408 100644
--- a/contrib/xml2/expected/xml2.out
+++ b/contrib/xml2/expected/xml2.out
@@ -207,3 +207,18 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
  
 (1 row)
 
+-- possible security exploit
+SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
+$$<xsl:stylesheet version="1.0"
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+      xmlns:sax="http://icl.com/saxon"
+      extension-element-prefixes="sax">
+
+  <xsl:template match="//foo">
+    <sax:output href="0wn3d.txt" method="text">
+      <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
+      <xsl:apply-templates/>
+    </sax:output>
+  </xsl:template>
+</xsl:stylesheet>$$);
+ERROR:  failed to apply stylesheet
diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out
index fda626e08c7f62040a0a106e964bb486bce10250..bac90e5a2a9d199f689def56f00425dd28b63d1c 100644
--- a/contrib/xml2/expected/xml2_1.out
+++ b/contrib/xml2/expected/xml2_1.out
@@ -151,3 +151,18 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
   </xsl:template>
 </xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
 ERROR:  xslt_process() is not available without libxslt
+-- possible security exploit
+SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
+$$<xsl:stylesheet version="1.0"
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+      xmlns:sax="http://icl.com/saxon"
+      extension-element-prefixes="sax">
+
+  <xsl:template match="//foo">
+    <sax:output href="0wn3d.txt" method="text">
+      <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
+      <xsl:apply-templates/>
+    </sax:output>
+  </xsl:template>
+</xsl:stylesheet>$$);
+ERROR:  xslt_process() is not available without libxslt
diff --git a/contrib/xml2/sql/xml2.sql b/contrib/xml2/sql/xml2.sql
index 4a996af71678b58027486859b208ccf9fce48d3f..ac49cfa7c52315ca48c4829e58253acc7eed49eb 100644
--- a/contrib/xml2/sql/xml2.sql
+++ b/contrib/xml2/sql/xml2.sql
@@ -122,3 +122,18 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
     </xsl:element>
   </xsl:template>
 </xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
+
+-- possible security exploit
+SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
+$$<xsl:stylesheet version="1.0"
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+      xmlns:sax="http://icl.com/saxon"
+      extension-element-prefixes="sax">
+
+  <xsl:template match="//foo">
+    <sax:output href="0wn3d.txt" method="text">
+      <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
+      <xsl:apply-templates/>
+    </sax:output>
+  </xsl:template>
+</xsl:stylesheet>$$);
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
index a93931d2618ccecaefa3a71fe752fcd52132302c..2f24b39bcc0043f0bdcba98023327359dc584a0a 100644
--- a/contrib/xml2/xslt_proc.c
+++ b/contrib/xml2/xslt_proc.c
@@ -26,6 +26,7 @@
 
 #include <libxslt/xslt.h>
 #include <libxslt/xsltInternals.h>
+#include <libxslt/security.h>
 #include <libxslt/transform.h>
 #include <libxslt/xsltutils.h>
 #endif   /* USE_LIBXSLT */
@@ -61,7 +62,8 @@ xslt_process(PG_FUNCTION_ARGS)
 	volatile xsltStylesheetPtr stylesheet = NULL;
 	volatile xmlDocPtr doctree = NULL;
 	volatile xmlDocPtr restree = NULL;
-	volatile xmlDocPtr ssdoc = NULL;
+	volatile xsltSecurityPrefsPtr xslt_sec_prefs = NULL;
+	volatile xsltTransformContextPtr xslt_ctxt = NULL;
 	volatile int resstat = -1;
 	xmlChar    *resstr = NULL;
 	int			reslen = 0;
@@ -83,36 +85,62 @@ xslt_process(PG_FUNCTION_ARGS)
 
 	PG_TRY();
 	{
-		/* Check to see if document is a file or a literal */
+		xmlDocPtr	ssdoc;
+		bool		xslt_sec_prefs_error;
 
-		if (VARDATA(doct)[0] == '<')
-			doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
-		else
-			doctree = xmlParseFile(text_to_cstring(doct));
+		/* Parse document */
+		doctree = xmlParseMemory((char *) VARDATA(doct),
+								 VARSIZE(doct) - VARHDRSZ);
 
 		if (doctree == NULL)
 			xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
 						"error parsing XML document");
 
 		/* Same for stylesheet */
-		if (VARDATA(ssheet)[0] == '<')
-		{
-			ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
-								   VARSIZE(ssheet) - VARHDRSZ);
-			if (ssdoc == NULL)
-				xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
-							"error parsing stylesheet as XML document");
+		ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
+							   VARSIZE(ssheet) - VARHDRSZ);
 
-			stylesheet = xsltParseStylesheetDoc(ssdoc);
-		}
-		else
-			stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet));
+		if (ssdoc == NULL)
+			xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+						"error parsing stylesheet as XML document");
+
+		/* After this call we need not free ssdoc separately */
+		stylesheet = xsltParseStylesheetDoc(ssdoc);
 
 		if (stylesheet == NULL)
 			xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
 						"failed to parse stylesheet");
 
-		restree = xsltApplyStylesheet(stylesheet, doctree, params);
+		xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
+
+		xslt_sec_prefs_error = false;
+		if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
+			xslt_sec_prefs_error = true;
+
+		if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
+								 xsltSecurityForbid) != 0)
+			xslt_sec_prefs_error = true;
+		if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
+								 xsltSecurityForbid) != 0)
+			xslt_sec_prefs_error = true;
+		if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
+								 xsltSecurityForbid) != 0)
+			xslt_sec_prefs_error = true;
+		if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
+								 xsltSecurityForbid) != 0)
+			xslt_sec_prefs_error = true;
+		if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
+								 xsltSecurityForbid) != 0)
+			xslt_sec_prefs_error = true;
+		if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
+			xslt_sec_prefs_error = true;
+
+		if (xslt_sec_prefs_error)
+			ereport(ERROR,
+					(errmsg("could not set libxslt security preferences")));
+
+		restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
+										  NULL, NULL, xslt_ctxt);
 
 		if (restree == NULL)
 			xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
@@ -128,6 +156,10 @@ xslt_process(PG_FUNCTION_ARGS)
 			xmlFreeDoc(restree);
 		if (doctree != NULL)
 			xmlFreeDoc(doctree);
+		if (xslt_sec_prefs != NULL)
+			xsltFreeSecurityPrefs(xslt_sec_prefs);
+		if (xslt_ctxt != NULL)
+			xsltFreeTransformContext(xslt_ctxt);
 		xsltCleanupGlobals();
 
 		pg_xml_done(xmlerrcxt, true);
@@ -139,6 +171,8 @@ xslt_process(PG_FUNCTION_ARGS)
 	xsltFreeStylesheet(stylesheet);
 	xmlFreeDoc(restree);
 	xmlFreeDoc(doctree);
+	xsltFreeSecurityPrefs(xslt_sec_prefs);
+	xsltFreeTransformContext(xslt_ctxt);
 	xsltCleanupGlobals();
 
 	pg_xml_done(xmlerrcxt, false);
diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml
index 47bac31f0c7de5821063a194a47dee066cc92641..ce5a2f0645bd06c1d32b3926c807f6455588438f 100644
--- a/doc/src/sgml/xml2.sgml
+++ b/doc/src/sgml/xml2.sgml
@@ -436,14 +436,6 @@ xslt_process(text document, text stylesheet, text paramlist) returns text
     contain commas!
    </para>
 
-   <para>
-    Also note that if either the document or stylesheet values do not
-    begin with a &lt; then they will be treated as URLs and libxslt will
-    fetch them. It follows that you can use <function>xslt_process</> as a
-    means to fetch the contents of URLs &mdash; you should be aware of the
-    security implications of this.
-   </para>
-
    <para>
     There is also a two-parameter version of <function>xslt_process</> which
     does not pass any parameters to the transformation.