class XmlInjectionDetector extends BasicInjectionDetector implements TaintFrameAdditionalVisitor {

    private static final String XML_INJECTION_TYPE = "POTENTIAL_XML_INJECTION";
    private static final String[] STRING_CONCAT_CLASS = new String[] {"java/lang/StringBuilder","java/lang/StringBuffer"};

    private static final InvokeMatcherBuilder STRINGBUILDER_APPEND = invokeInstruction() //
            .atClass(STRING_CONCAT_CLASS).atMethod("append");

    private static final boolean DEBUG = false;

    public XmlInjectionDetector(BugReporter bugReporter) {
        super(bugReporter);

        for(String variant: STRING_CONCAT_CLASS) { //Small hack to avoid loading a signature files for two functions.
            addParsedInjectionPoint(variant+".append(Ljava/lang/String;)L"+variant+";",new InjectionPoint(new int[] {0}, XML_INJECTION_TYPE));
        }
        registerVisitor(this);
    }

    @Override
    protected int getPriorityFromTaintFrame(TaintFrame taintFrame, int offset) throws DataflowAnalysisException {<FILL_FUNCTION_BODY>}

    @Override
    public void visitInvoke(InvokeInstruction invoke, MethodGen methodGen, TaintFrame frameType, List<Taint> parameters, ConstantPoolGen cpg) throws DataflowAnalysisException {

        if(STRINGBUILDER_APPEND.matches(invoke,cpg)) {

            Taint appendedTaint = parameters.get(0);
            String appendedString = appendedTaint.getConstantValue();
            if(appendedString!= null) {

                //When the string with a tag is sent to the append function.
                //The StringBuilder class will be tagged as XML_VALUE
                if(appendedString.contains("<") && appendedString.contains(">")) {
                    appendedTaint.addTag(Taint.Tag.XML_VALUE);
                    frameType.getStackValue(0).addTag(Taint.Tag.XML_VALUE);
                }
            }



        }
    }

    @Override
    public void visitReturn(MethodGen methodGen, Taint returnValue, ConstantPoolGen cpg) throws Exception {

    }

    @Override
    public void visitLoad(LoadInstruction instruction, MethodGen methodGen, TaintFrame frameType, int numProduced, ConstantPoolGen cpg) {

    }

    @Override
    public void visitField(FieldInstruction put, MethodGen methodGen, TaintFrame frameType, Taint taint, int numProduced, ConstantPoolGen cpg) throws Exception {

    }

    /**
     * Before we added new tag to the taint analysis and add more effort, here is a linear search on the constant pool.
     * Constant pool include all the constant use in the code of the class. It contains class references and string value.
     *
     * If there are no XML in string in the class, we are add not going to run this additional visitor.
     *
     * @param classContext Information about the class that is about to be analyzed
     * @return
     */
    @Override
    public boolean shouldAnalyzeClass(ClassContext classContext) {
        ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen();
        boolean stringConcat = false;
        boolean hasOpenTagInString = false;
        for (String requiredClass : STRING_CONCAT_CLASS) {
            if (constantPoolGen.lookupUtf8(requiredClass) != -1) {
                stringConcat = true;
                break;
            }
        }
        for(int i=0;i<constantPoolGen.getSize();i++) {
            Constant c = constantPoolGen.getConstant(i);
            if(c instanceof ConstantUtf8) {
                ConstantUtf8 utf8value = (ConstantUtf8) c;
                if(utf8value.getBytes().contains("<")) {
                    hasOpenTagInString = true;
                    break;
                }
            }
        }
        return stringConcat && hasOpenTagInString;
    }
}

        Taint taint0 = taintFrame.getStackValue(0);
        Taint taint1 = taintFrame.getStackValue(1);

        /**
         * If the value argument passed to append is unsafe (not constant)[1] and not sanitize for XML (XSS_SAFE) [2]
         * and the StringBuilder to which the dynamic value is added is within XML tags [3]
         * [1] && [2] && [3]
         */
        if (!taint0.isSafe() && !taint0.hasTag(Taint.Tag.XSS_SAFE) && taint1.hasTag(Taint.Tag.XML_VALUE)) {
            return Priorities.NORMAL_PRIORITY;
        }
        else {
            return Priorities.IGNORE_PRIORITY;
        }
    
<methods>public void registerVisitor(com.h3xstream.findsecbugs.taintanalysis.TaintFrameAdditionalVisitor) <variables>static com.h3xstream.findsecbugs.injection.ClassMethodSignature OBJECT,private static final com.h3xstream.findsecbugs.injection.SinksLoader SINKS_LOADER,private final Map<com.h3xstream.findsecbugs.injection.ClassMethodSignature,com.h3xstream.findsecbugs.injection.InjectionPoint> injectionMap